MySQL 8.0 参考手册  / 第24章分区  / 24.2 分区类型  /  22.2.6 子分区

22.2.6 子分区

子分区(也称为 复合分区)是分区表中每个分区的进一步划分。考虑以下 CREATE TABLE语句:

CREATE TABLE ts (id INT, purchased DATE)
    PARTITION BY RANGE( YEAR(purchased) )
    SUBPARTITION BY HASH( TO_DAYS(purchased) )
    SUBPARTITIONS 2 (
        PARTITION p0 VALUES LESS THAN (1990),
        PARTITION p1 VALUES LESS THAN (2000),
        PARTITION p2 VALUES LESS THAN MAXVALUE
    );

ts有 3 个RANGE 分区。这些分区p0中的每一个—— p1、 和—— 都p2进一步分为 2 个子分区。实际上,整个表被划分为多个 3 * 2 = 6分区。但是,由于PARTITION BY RANGE子句的作用,前 2 个只存储列中值小于 1990 的那些记录purchased

在 MySQL 5.7 中,可以对按RANGE或 分区的表进行子分区LIST。子分区可以使用 HASHKEY分区。这也称为复合分区

笔记

SUBPARTITION BY HASH和 通常分别遵循与和 SUBPARTITION BY KEY相同的语法规则。一个例外是(与 不同)当前不支持默认列,因此必须指定用于此目的的列,即使该表具有显式主键。这是一个我们正在努力解决的已知问题;有关更多信息和示例, 请参阅 子分区问题。PARTITION BY HASHPARTITION BY KEYSUBPARTITION BY KEYPARTITION BY KEY

也可以使用 SUBPARTITION子句显式定义子分区以指定各个子分区的选项。例如,创建与ts前面示例中所示相同的表的更详细的方式是:

CREATE TABLE ts (id INT, purchased DATE)
    PARTITION BY RANGE( YEAR(purchased) )
    SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
        PARTITION p0 VALUES LESS THAN (1990) (
            SUBPARTITION s0,
            SUBPARTITION s1
        ),
        PARTITION p1 VALUES LESS THAN (2000) (
            SUBPARTITION s2,
            SUBPARTITION s3
        ),
        PARTITION p2 VALUES LESS THAN MAXVALUE (
            SUBPARTITION s4,
            SUBPARTITION s5
        )
    );

此处列出了一些需要注意的句法项目:

  • 每个分区必须具有相同数量的子分区。

  • 如果您 SUBPARTITION在分区表的任何分区上显式定义任何子分区,则必须全部定义它们。换句话说,以下语句失败:

    CREATE TABLE ts (id INT, purchased DATE)
        PARTITION BY RANGE( YEAR(purchased) )
        SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
            PARTITION p0 VALUES LESS THAN (1990) (
                SUBPARTITION s0,
                SUBPARTITION s1
            ),
            PARTITION p1 VALUES LESS THAN (2000),
            PARTITION p2 VALUES LESS THAN MAXVALUE (
                SUBPARTITION s2,
                SUBPARTITION s3
            )
        );

    即使它包含一个 SUBPARTITIONS 2子句,该语句仍然会失败。

  • 每个SUBPARTITION子句必须(至少)包含子分区的名称。否则,您可以为子分区设置任何所需的选项或允许它采用该选项的默认设置。

  • 子分区名称在整个表中必须是唯一的。例如,以下CREATE TABLE语句在 MySQL 5.7 中有效:

    CREATE TABLE ts (id INT, purchased DATE)
        PARTITION BY RANGE( YEAR(purchased) )
        SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
            PARTITION p0 VALUES LESS THAN (1990) (
                SUBPARTITION s0,
                SUBPARTITION s1
            ),
            PARTITION p1 VALUES LESS THAN (2000) (
                SUBPARTITION s2,
                SUBPARTITION s3
            ),
            PARTITION p2 VALUES LESS THAN MAXVALUE (
                SUBPARTITION s4,
                SUBPARTITION s5
            )
        );

子分区可以与特别大 MyISAM的表一起使用,以跨多个磁盘分布数据和索引。假设您有 6 个磁盘安装为/disk0/disk1/disk2等。现在考虑以下示例:

CREATE TABLE ts (id INT, purchased DATE)
    ENGINE = MYISAM
    PARTITION BY RANGE( YEAR(purchased) )
    SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
        PARTITION p0 VALUES LESS THAN (1990) (
            SUBPARTITION s0
                DATA DIRECTORY = '/disk0/data'
                INDEX DIRECTORY = '/disk0/idx',
            SUBPARTITION s1
                DATA DIRECTORY = '/disk1/data'
                INDEX DIRECTORY = '/disk1/idx'
        ),
        PARTITION p1 VALUES LESS THAN (2000) (
            SUBPARTITION s2
                DATA DIRECTORY = '/disk2/data'
                INDEX DIRECTORY = '/disk2/idx',
            SUBPARTITION s3
                DATA DIRECTORY = '/disk3/data'
                INDEX DIRECTORY = '/disk3/idx'
        ),
        PARTITION p2 VALUES LESS THAN MAXVALUE (
            SUBPARTITION s4
                DATA DIRECTORY = '/disk4/data'
                INDEX DIRECTORY = '/disk4/idx',
            SUBPARTITION s5
                DATA DIRECTORY = '/disk5/data'
                INDEX DIRECTORY = '/disk5/idx'
        )
    );

在这种情况下,单独的磁盘用于数据和每个RANGE. 许多其他变化是可能的;另一个例子可能是:

CREATE TABLE ts (id INT, purchased DATE)
    ENGINE = MYISAM
    PARTITION BY RANGE(YEAR(purchased))
    SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
        PARTITION p0 VALUES LESS THAN (1990) (
            SUBPARTITION s0a
                DATA DIRECTORY = '/disk0'
                INDEX DIRECTORY = '/disk1',
            SUBPARTITION s0b
                DATA DIRECTORY = '/disk2'
                INDEX DIRECTORY = '/disk3'
        ),
        PARTITION p1 VALUES LESS THAN (2000) (
            SUBPARTITION s1a
                DATA DIRECTORY = '/disk4/data'
                INDEX DIRECTORY = '/disk4/idx',
            SUBPARTITION s1b
                DATA DIRECTORY = '/disk5/data'
                INDEX DIRECTORY = '/disk5/idx'
        ),
        PARTITION p2 VALUES LESS THAN MAXVALUE (
            SUBPARTITION s2a,
            SUBPARTITION s2b
        )
    );

这里,存储如下:

  • 日期在 1990 年之前的行purchased占用大量空间,因此分为 4 种方式,一个单独的磁盘专用于数据和两个子分区(s0as0b)中的每一个的索引 partition p0。换句话说:

    • 子分区的数据s0a存储在/disk0.

    • 子分区的索引s0a存储在/disk1.

    • 子分区的数据s0b存储在/disk2.

    • 子分区的索引s0b存储在/disk3.

  • 包含从 1990 年到 1999 年(分区 p1)的日期的行不需要像 1990 年之前的行那么多的空间。这些被分成 2 个磁盘(/disk4/disk5)而不是 4 个磁盘,就像存储在 中的遗留记录一样p0

    • 属于p1第一个子分区 ( s1a) 的数据和索引存储在/disk4— 中的数据 /disk4/data和 中的索引 /disk4/idx

    • 属于p1第二个子分区 ( s1b) 的数据和索引存储在/disk5— 中的数据 /disk5/data和 中的索引 /disk5/idx

  • 反映从 2000 年到现在的日期的行(分区p2)占用的空间没有前两个范围中的任何一个所需的空间多。目前,将所有这些存储在默认位置就足够了。

    将来,当从 2000 年开始的十年的购买数量增长到默认位置不再提供足够空间时,可以使用ALTER TABLE ... REORGANIZE PARTITION语句移动相应的行。有关如何完成此操作的说明, 请参见 第 22.3 节,“分区管理” 。

当服务器 SQL 模式生效时,分区定义中不允许 使用DATA DIRECTORY和选项。在 MySQL 5.7 中,定义子分区时也不允许使用这些选项(错误 #42954)。 INDEX DIRECTORYNO_DIR_IN_CREATE