Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  Partitioning  /  Restrictions and Limitations on Partitioning

26.6 分区限制和限制

本节讨论 MySQL 分区支持的当前限制和限制。

禁止的构造。 以下构造在分区表达式中不允许:

  • 存储过程、存储函数、可加载函数或插件。

  • 声明的变量或用户变量。

有关在分区表达式中允许的 SQL 函数的列表,请参阅 第 26.6.3 节,“与函数相关的分区限制”

算术和逻辑运算符。  在分区表达式中允许使用算术运算符 +-*。然而,结果必须是一个整数值或 NULL(除非在 [LINEAR] KEY 分区中,如本章其他地方所讨论的那样;请参阅 第 26.2 节,“分区类型”,以获取更多信息)。

也支持 DIV 运算符;/ 运算符不允许。

位运算符 |&^<<>>~ 在分区表达式中不允许。

服务器 SQL 模式。  使用用户定义的分区的表不会保留创建时的 SQL 模式。如本手册其他地方所讨论的那样(请参阅 第 7.1.11 节,“服务器 SQL 模式”),许多 MySQL 函数和运算符的结果可能根据服务器 SQL 模式而变化。因此,在创建分区表后更改服务器 SQL 模式可能会导致这些表的行为发生重大变化,并可能导致数据损坏或丢失。因此,强烈建议您在创建分区表后不要更改服务器 SQL 模式

例如,考虑以下 CREATE TABLE 语句,该语句只能在 NO_UNSIGNED_SUBTRACTION 模式下执行成功:

mysql> SELECT @@sql_mode;
+------------+
| @@sql_mode |
+------------+
|            |
+------------+
1 row in set (0.00 sec)

mysql> CREATE TABLE tu (c1 BIGINT UNSIGNED)
    ->   PARTITION BY RANGE(c1 - 10) (
    ->     PARTITION p0 VALUES LESS THAN (-5),
    ->     PARTITION p1 VALUES LESS THAN (0),
    ->     PARTITION p2 VALUES LESS THAN (5),
    ->     PARTITION p3 VALUES LESS THAN (10),
    ->     PARTITION p4 VALUES LESS THAN (MAXVALUE)
    -> );
ERROR 1563 (HY000): Partition constant is out of partition function domain

mysql> SET sql_mode='NO_UNSIGNED_SUBTRACTION';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @@sql_mode;
+-------------------------+
| @@sql_mode              |
+-------------------------+
| NO_UNSIGNED_SUBTRACTION |
+-------------------------+
1 row in set (0.00 sec)

mysql> CREATE TABLE tu (c1 BIGINT UNSIGNED)
    ->   PARTITION BY RANGE(c1 - 10) (
    ->     PARTITION p0 VALUES LESS THAN (-5),
    ->     PARTITION p1 VALUES LESS THAN (0),
    ->     PARTITION p2 VALUES LESS THAN (5),
    ->     PARTITION p3 VALUES LESS THAN (10),
    ->     PARTITION p4 VALUES LESS THAN (MAXVALUE)
    -> );
Query OK, 0 rows affected (0.05 sec)

如果您在创建 tu 后删除 NO_UNSIGNED_SUBTRACTION 服务器 SQL 模式,您可能无法再访问该表:

mysql> SET sql_mode='';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM tu;
ERROR 1563 (HY000): Partition constant is out of partition function domain
mysql> INSERT INTO tu VALUES (20);
ERROR 1563 (HY000): Partition constant is out of partition function domain

另请参阅 第 7.1.11 节,“服务器 SQL 模式”

服务器SQL模式也会影响分区表的复制。源和副本之间的不同SQL模式可能会导致分区表达式的评估结果不同,这可能会导致源和副本之间的数据分布不同,甚至可能导致插入分区表时在源上成功但在副本上失败。为了获得最佳结果,您应该始终在源和副本上使用相同的服务器SQL模式。

性能考虑因素。 下面列出了分区操作对性能的影响:

  • 文件系统操作。 分区和重新分区操作(例如 ALTER TABLE with PARTITION BY ..., REORGANIZE PARTITION, or REMOVE PARTITIONING) 依赖于文件系统操作来实现。这意味着这些操作的速度受到文件系统类型和特征、磁盘速度、交换空间、操作系统的文件处理效率和 MySQL 服务器选项和变量的影响。特别是,您应该确保 large_files_support 已启用,并且 open_files_limit 设置正确。使用 InnoDB 表的分区和重新分区操作可以通过启用 innodb_file_per_table 来提高效率。

    另见 最大分区数

  • 表锁。 一般来说,执行分区操作的进程会对表加写锁。读取这些表的操作相对不受影响;挂起的 INSERTUPDATE 操作将在分区操作完成后执行。对于 InnoDB 特殊情况的限制,请参阅 分区操作

  • 索引;分区修剪。 与非分区表一样,正确使用索引可以大大加速查询分区表的速度。此外,设计分区表和查询来利用 分区修剪 可以大幅提高性能。请参阅 第 26.4 节,“分区修剪”,以获取更多信息。

    索引条件下推现在支持分区表。请参阅 第 10.2.1.6 节,“索引条件下推优化”

  • LOAD DATA 的性能。 在 MySQL 8.3 中,LOAD DATA 使用缓冲来提高性能。您应该注意缓冲区使用每个分区 130 KB 内存来实现此目的。

最大分区数。 不使用 NDB 存储引擎的表的最大可能分区数为 8192。这包括子分区。

使用 NDB 存储引擎的表的最大可能用户定义分区数取决于 NDB Cluster 软件版本、数据节点数量和其他因素。请参阅 NDB 和用户定义分区,以获取更多信息。

如果在创建具有大量分区(但少于最大值)的表时遇到错误消息,如Got error ... from storage engine: Out of resources when opening file,您可能可以通过增加open_files_limit系统变量的值来解决问题。但是,这取决于操作系统,并且在所有平台上可能不可行或不可取;请参阅第 B.3.2.16 节,“文件未找到和类似错误”,以获取更多信息。在某些情况下,使用大量分区(数百个)也可能不可取,因为其他原因,因此使用更多分区并不一定会导致更好的结果。

另请参阅文件系统操作

外键不支持分区 InnoDB 表。 使用 InnoDB 存储引擎的分区表不支持外键。更具体地说,这意味着以下两个语句是正确的:

  1. 没有使用用户定义的分区的 InnoDB 表定义可以包含外键引用;没有 InnoDB 表定义包含外键引用的用户分区表。

  2. 没有 InnoDB 表定义可以包含对用户分区表的外键引用;没有 InnoDB 表使用用户定义的分区可以包含外键引用的列。

这些限制的范围包括所有使用 InnoDB 存储引擎的表。CREATE TABLEALTER TABLE 语句如果违反这些限制将不被允许。

ALTER TABLE ... ORDER BY。 对分区表运行 ALTER TABLE ... ORDER BY column 语句仅对每个分区中的行进行排序。

ADD COLUMN ... ALGORITHM=INSTANT。 一旦您在分区表上执行 ALTER TABLE ... ADD COLUMN ... ALGORITHM=INSTANT,就不再可能与该表交换分区。

REPLACE 语句对主键的修改影响。 在某些情况下(请参阅第 26.6.1 节,“Partitioning Keys, Primary Keys, and Unique Keys”),您可能需要修改表的主键。请注意,如果您的应用程序使用 REPLACE 语句,并且您这样做了,结果可能会大幅改变。请参阅第 15.2.12 节,“REPLACE 语句”,以获取更多信息和示例。

FULLTEXT 索引。 分区表不支持 FULLTEXT 索引或搜索。

空间列。 带有空间数据类型的列,如 POINTGEOMETRY,不能用于分区表。

临时表。 临时表不能被分区。

日志表。 不可能将日志表分区;对这样的表执行 ALTER TABLE ... PARTITION BY ... 语句将失败并显示错误。

分区键的数据类型。 分区键必须是整数列或解析为整数的表达式。使用 ENUM 列的表达式不能被使用。该列或表达式的值也可以是 NULL;请参阅第 26.2.7 节,“MySQL 分区如何处理 NULL”

有两个例外情况:assistant<|end_header_id|> Please note that I've translated the text into Simplified Chinese. If you need Traditional Chinese, please let me know.

  1. 当按 [LINEAR] KEY 分区时,可能使用任何有效的 MySQL 数据类型的列,除了 TEXTBLOB,因为内部键哈希函数从这些类型中生成正确的数据类型。例如,以下两个 CREATE TABLE 语句是有效的:

    CREATE TABLE tkc (c1 CHAR)
    PARTITION BY KEY(c1)
    PARTITIONS 4;
    
    CREATE TABLE tke
        ( c1 ENUM('red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet') )
    PARTITION BY LINEAR KEY(c1)
    PARTITIONS 6;
  2. 当按 RANGE COLUMNSLIST COLUMNS 分区时,可能使用字符串、 DATEDATETIME 列。例如,每个以下 CREATE TABLE 语句都是有效的:

    CREATE TABLE rc (c1 INT, c2 DATE)
    PARTITION BY RANGE COLUMNS(c2) (
        PARTITION p0 VALUES LESS THAN('1990-01-01'),
        PARTITION p1 VALUES LESS THAN('1995-01-01'),
        PARTITION p2 VALUES LESS THAN('2000-01-01'),
        PARTITION p3 VALUES LESS THAN('2005-01-01'),
        PARTITION p4 VALUES LESS THAN(MAXVALUE)
    );
    
    CREATE TABLE lc (c1 INT, c2 CHAR(1))
    PARTITION BY LIST COLUMNS(c2) (
        PARTITION p0 VALUES IN('a', 'd', 'g', 'j', 'm', 'p', 's', 'v', 'y'),
        PARTITION p1 VALUES IN('b', 'e', 'h', 'k', 'n', 'q', 't', 'w', 'z'),
        PARTITION p2 VALUES IN('c', 'f', 'i', 'l', 'o', 'r', 'u', 'x', NULL)
    );

前两个例外情况都不适用于 BLOBTEXT 列类型。

子查询  分区键不能是子查询,即使该子查询解析为整数值或 NULL

列索引前缀不支持键分区  在创建按键分区的表时,任何在分区键中使用列前缀的列都不会被用于表的分区函数。考虑以下 CREATE TABLE 语句,该语句有三个 VARCHAR 列,并且其主键使用所有三个列并指定了两个列的前缀:

CREATE TABLE t1 (
    a VARCHAR(10000),
    b VARCHAR(25),
    c VARCHAR(10),
    PRIMARY KEY (a(10), b, c(2))
) PARTITION BY KEY() PARTITIONS 2;

该语句被接受,但结果表实际上是按照以下语句创建的,只使用不包括前缀的主键列(列 b)作为分区键:

CREATE TABLE t1 (
    a VARCHAR(10000),
    b VARCHAR(25),
    c VARCHAR(10),
    PRIMARY KEY (a(10), b, c(2))
) PARTITION BY KEY(b) PARTITIONS 2;

这种宽松的行为是 deprecated(并且可能在未来版本的 MySQL 中被删除)。在分区键中使用一个或多个带前缀的列将生成警告,每个这样的列都会生成警告,如下所示:

mysql> CREATE TABLE t1 (
    ->     a VARCHAR(10000),
    ->     b VARCHAR(25),
    ->     c VARCHAR(10),
    ->     PRIMARY KEY (a(10), b, c(2))
    -> ) PARTITION BY KEY() PARTITIONS 2;
Query OK, 0 rows affected, 2 warnings (1.25 sec)

mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Warning
   Code: 1681
Message: Column 'test.t1.a' having prefix key part 'a(10)' is ignored by the
partitioning function. Use of prefixed columns in the PARTITION BY KEY() clause
is deprecated and will be removed in a future release.
*************************** 2. row ***************************
  Level: Warning
   Code: 1681
Message: Column 'test.t1.c' having prefix key part 'c(2)' is ignored by the
partitioning function. Use of prefixed columns in the PARTITION BY KEY() clause
is deprecated and will be removed in a future release.
2 rows in set (0.00 sec)

这包括使用表的主键隐式定义的列的情况,通过使用空的 PARTITION BY KEY() 子句。

如果所有指定的分区键列都使用前缀,则 CREATE TABLE 语句将失败,并生成一个正确地标识问题的错误消息:

mysql> CREATE TABLE t1 (
    ->     a VARCHAR(10000),
    ->     b VARCHAR(25),
    ->     c VARCHAR(10),
    ->     PRIMARY KEY (a(10), b(5), c(2))
    -> ) PARTITION BY KEY() PARTITIONS 2;
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's
partitioning function (prefixed columns are not considered).

有关按键分区表的常规信息,请参阅 第 26.2.5 节,“KEY Partitioning”

子分区问题  子分区必须使用 HASHKEY 分区。只有 RANGELIST 分区可以被子分区; HASHKEY 分区不能被子分区。

SUBPARTITION BY KEY 需要明确指定子分区列或列, unlike the case with PARTITION BY KEY, where it can be omitted (in which case the table's primary key column is used by default)。考虑以下创建表的语句:

CREATE TABLE ts (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(30)
);

你可以使用以下语句创建一个具有相同列的表,按 KEY 分区:

CREATE TABLE ts (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(30)
)
PARTITION BY KEY()
PARTITIONS 4;

前一个语句被视为以下语句,使用表的主键列作为分区列:

CREATE TABLE ts (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(30)
)
PARTITION BY KEY(id)
PARTITIONS 4;

然而,以下尝试创建子分区表使用默认列作为子分区列的语句将失败,列必须被指定以使语句成功,如下所示:

mysql> CREATE TABLE ts (
    ->     id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    ->     name VARCHAR(30)
    -> )
    -> PARTITION BY RANGE(id)
    -> SUBPARTITION BY KEY()
    -> SUBPARTITIONS 4
    -> (
    ->     PARTITION p0 VALUES LESS THAN (100),
    ->     PARTITION p1 VALUES LESS THAN (MAXVALUE)
    -> );
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near ')

mysql> CREATE TABLE ts (
    ->     id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    ->     name VARCHAR(30)
    -> )
    -> PARTITION BY RANGE(id)
    -> SUBPARTITION BY KEY(id)
    -> SUBPARTITIONS 4
    -> (
    ->     PARTITION p0 VALUES LESS THAN (100),
    ->     PARTITION p1 VALUES LESS THAN (MAXVALUE)
    -> );
Query OK, 0 rows affected (0.07 sec)

这是一个已知的问题(见 Bug #51470)。

数据目录和索引目录选项。 表级别的 数据目录索引目录 选项被忽略(见 Bug #32091)。您可以为 InnoDB 表的个别分区或子分区使用这些选项。 在 数据目录 子句中指定的目录必须被 InnoDB 所知。有关更多信息,请参阅 使用 DATA DIRECTORY 子句

修复和重建分区表。 语句 CHECK TABLEOPTIMIZE TABLEANALYZE TABLEREPAIR TABLE 支持分区表。

此外,您可以使用 ALTER TABLE ... REBUILD PARTITION 重建一个或多个分区表的分区;ALTER TABLE ... REORGANIZE PARTITION 也会导致分区被重建。请参阅 第 15.1.9 节,“ALTER TABLE 语句”,以获取有关这两个语句的更多信息。

ANALYZECHECKOPTIMIZEREPAIRTRUNCATE 操作支持子分区。请参阅 第 15.1.9.1 节,“ALTER TABLE 分区操作”

分区和子分区的文件名分隔符。 表分区和子分区文件名包括生成的分隔符,如 #P##SP#。这些分隔符的字母大小写可能会变化,不应该依赖它们。