22.2.6 Subpartitioning
子分区(也称为复合分区)是分区 table 中每个分区的进一步划分。考虑以下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
);
tablets
具有 3 个RANGE
分区。每个分区p0
,p1
和p2
进一步分为 2 个子分区。实际上,整个 table 分为3 * 2 = 6
个分区。但是,由于PARTITION BY RANGE
子句的作用,其中的前 2 个仅在purchased
列中存储值小于 1990 的那些记录。
在 MySQL 5.7 中,可以对被RANGE
或LIST
分区的 table 进行子分区。子分区可以使用HASH
或KEY
分区。这也称为复合分区。
Note
SUBPARTITION BY HASH
和SUBPARTITION BY KEY
通常分别遵循与PARTITION BY HASH
和PARTITION BY KEY
相同的语法规则。exceptions 是SUBPARTITION BY KEY
(与PARTITION BY KEY
不同)当前不支持默认列,因此即使 table 具有显式主键,也必须指定用于此目的的列。这是我们正在努力解决的已知问题;有关更多信息和示例,请参见子分区问题。
也可以使用SUBPARTITION
子句显式定义子分区,以指定各个子分区的选项。例如,如上例所示,创建相同 tablets
的更为冗长的方式是:
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
)
);
这里列出了一些语法上的注意事项:
-
每个分区必须具有相同数量的子分区。
-
如果在分区 table 的任何分区上使用
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
子句必须(至少)包括该子分区的名称。否则,您可以为子分区设置任何所需的选项,或允许其采用该选项的默认设置。 -
子分区名称在整个 table 中必须唯一。例如,以下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
)
);
子分区可以与特别大的MyISAMtable 一起使用,以在许多磁盘上分配数据和索引。假设您安装了 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
)
);
在这里,存储如下:
-
具有
purchased
日期的 1990 年之前的行会占用大量空间,因此被分成 4 种方式,其中一个单独的磁盘专用于数据和组成分区p0
的两个子分区(s0a
和s0b
)的索引。换一种说法: -
子分区
s0a
的数据存储在/disk0
上。-
子分区
s0a
的索引存储在/disk1
上。 -
子分区
s0b
的数据存储在/disk2
上。 -
子分区
s0b
的索引存储在/disk3
上。
-
-
包含 1990 年到 1999 年(分区
p1
)之间日期的行所需要的空间没有 1990 年之前的空间大。它们被分成 2 个磁盘(/disk4
和/disk5
),而不是像p0
中存储的旧记录那样划分为 4 个磁盘: -
属于
p1
的第一个子分区(s1a
)的数据和索引存储在/disk4
上-/disk4/data
中的数据和/disk4/idx
中的索引。- 属于
p1
的第二子分区(s1b
)的数据和索引存储在/disk5
上-/disk5/data
中的数据和/disk5/idx
中的索引。
- 属于
-
反映从 2000 年到现在(分区
p2
)的日期的行所占用的空间不如前两个范围中的任何一个所需。当前,将所有这些存储在默认位置就足够了。
将来,当从 2000 年开始的十年中的购买数量增加到默认位置不再提供足够空间的程度时,可以使用ALTER TABLE ... REORGANIZE PARTITION
语句移动相应的行。有关如何执行此操作的说明,请参见第 22.3 节“分区 Management”。
当NO_DIR_IN_CREATE服务器 SQL 模式生效时,分区定义中不允许DATA DIRECTORY
和INDEX DIRECTORY
选项。在 MySQL 5.7 中,定义子分区时也不允许使用这些选项(错误#42954)。