本节概述了 MySQL 8.4 中的分区概念。
有关分区限制和功能局限性的信息,请参见 第 26.6 节“分区限制和局限性”。
SQL 标准没有提供多少关于数据存储的物理方面的指导。SQL 语言本身旨在独立于任何数据结构或底层架构、表、行或列的媒体而工作。尽管如此,大多数高级数据库管理系统已经发展出了一些方法来确定用于存储特定数据片段的物理位置,这些数据片段指的是文件系统、硬件或两者兼而有之。在 MySQL 中,InnoDB
存储引擎长期以来一直支持表空间的概念(请参见 第 17.6.3 节“表空间”),而 MySQL 服务器,即使在引入分区之前,也可以配置为使用不同的物理目录来存储不同的数据库(请参见 第 10.12.2 节“使用符号链接”,了解有关如何执行此操作的说明)。
分区 进一步扩展了此概念,使您能够根据可以根据需要设置的规则,在文件系统中分发各个表的某些部分。实际上,表的不同部分以不同的位置存储为单独的表。用于完成数据划分的用户选择的规则称为 分区函数,在 MySQL 中,该函数可以是模数、对一组范围或值列表的简单匹配、内部哈希函数或线性哈希函数。根据用户指定的分区类型选择函数,并将用户提供的表达式的值作为其参数。此表达式可以是列值、作用于一个或多个列值的函数,或一组一个或多个列值,具体取决于所使用的分区类型。
对于 RANGE
、LIST
和 [LINEAR
] HASH
分区,分区列的值将传递给分区函数,该函数返回一个整数,表示该特定记录应存储在哪个分区的编号。此函数必须是非常量且非随机的。它可能不包含任何查询,但可以使用在 MySQL 中有效的 SQL 表达式,只要该表达式返回 NULL
或一个整数 intval
,使得
-MAXVALUE <= intval <= MAXVALUE
(MAXVALUE
用于表示相关整数类型的最小上限。 -MAXVALUE
代表最大下限。)
对于 [LINEAR
] KEY
、RANGE COLUMNS
和 LIST COLUMNS
分区,分区表达式包含一个或多个列的列表。
对于 [LINEAR
] KEY
分区,分区函数由 MySQL 提供。
有关允许的分区列类型和分区函数的更多信息,请参见 第 26.2 节“分区类型”,以及 第 15.1.20 节“CREATE TABLE 语句”,其中提供了分区语法描述和更多示例。有关分区函数限制的信息,请参见 第 26.6.3 节“与函数相关的分区限制”。
这被称为 水平分区——也就是说,表的不同行可以分配到不同的物理分区。MySQL 8.4 不支持 垂直分区,其中表的不同列分配到不同的物理分区。目前没有计划在 MySQL 中引入垂直分区。
要创建分区表,您必须使用支持分区的存储引擎。在 MySQL 8.4 中,同一个分区表的各个分区必须使用相同的存储引擎。但是,没有什么可以阻止您对同一个 MySQL 服务器上的不同分区表,甚至同一个数据库中的不同分区表使用不同的存储引擎。
在 MySQL 8.4 中,唯一支持分区的存储引擎是 InnoDB
和 NDB
。分区不能与不支持分区的存储引擎一起使用;这些引擎包括 MyISAM
、MERGE
、CSV
和 FEDERATED
存储引擎。
使用 NDB
可以在 KEY
或 LINEAR KEY
上进行分区,但对于使用此存储引擎的表,不支持其他类型的用户定义分区。此外,使用用户定义分区的 NDB
表必须具有明确的主键,并且表的分区表达式中引用的任何列都必须是主键的一部分。但是,如果在用于创建或修改用户分区 NDB
表的 CREATE TABLE
或 ALTER TABLE
语句的 PARTITION BY KEY
或 PARTITION BY LINEAR KEY
子句中没有列出任何列,则该表不需要具有明确的主键。有关更多信息,请参见 第 25.2.7.1 节“NDB 集群中的 SQL 语法不兼容”。
创建分区表时,默认存储引擎与创建任何其他表时一样使用;要覆盖此行为,只需使用 [STORAGE] ENGINE
选项,就像您对非分区表所做的那样。目标存储引擎必须提供本机分区支持,否则语句将失败。您应该记住,[STORAGE] ENGINE
(和其他表选项)需要在 CREATE TABLE
语句中使用任何分区选项之前列出。此示例展示了如何创建一个通过哈希分区成 6 个分区并使用 InnoDB
存储引擎的表(无论 default_storage_engine
的值如何)
CREATE TABLE ti (id INT, amount DECIMAL(7,2), tr_date DATE)
ENGINE=INNODB
PARTITION BY HASH( MONTH(tr_date) )
PARTITIONS 6;
每个 PARTITION
子句都可以包含 [STORAGE] ENGINE
选项,但在 MySQL 8.4 中,此选项没有任何影响。
除非另有说明,否则本讨论中其余示例假设 default_storage_engine
为 InnoDB
。
分区适用于表的全部数据和索引;您不能只分区数据而不分区索引,反之亦然,也不能只分区表的一部分。
每个分区的 数据和索引可以使用 DATA DIRECTORY
和 INDEX DIRECTORY
选项(用于 CREATE TABLE
语句的 PARTITION
子句)分配到特定目录。
仅 DATA DIRECTORY
选项支持 InnoDB
表的各个分区和子分区。在 DATA DIRECTORY
子句中指定的目录必须为 InnoDB
所知。有关更多信息,请参见 使用 DATA DIRECTORY 子句。
表的分区表达式中使用的所有列都必须是表可能具有的每个唯一键的一部分,包括任何主键。这意味着无法分区如以下 SQL 语句创建的这样的表
CREATE TABLE tnp (
id INT NOT NULL AUTO_INCREMENT,
ref BIGINT NOT NULL,
name VARCHAR(255),
PRIMARY KEY pk (id),
UNIQUE KEY uk (name)
);
由于键 pk
和 uk
没有公共列,因此在分区表达式中没有可用列。在这种情况下,可能的解决方法包括将 name
列添加到表的 主键,将 id
列添加到 uk
,或者完全删除唯一键。有关更多信息,请参阅 第 26.6.1 节,“分区键、主键和唯一键”。
此外,MAX_ROWS
和 MIN_ROWS
可用于分别确定每个分区可以存储的最大和最小行数。有关这些选项的更多信息,请参阅 第 26.3 节,“分区管理”。
MAX_ROWS
选项也可以用于创建具有额外分区的 NDB 集群表,从而允许存储更多散列索引。有关更多信息,请参阅 DataMemory
数据节点配置参数的文档以及 第 25.2.2 节,“NDB 集群节点、节点组、片段副本和分区”。
以下是分区的一些优点:
分区使得在一个表中存储比单个磁盘或文件系统分区上可以容纳的更多数据成为可能。
不再有用的数据通常可以通过删除仅包含该数据的分区(或多个分区)轻松地从分区表中删除。相反,在某些情况下,添加新数据可以通过添加一个或多个用于存储该数据的 新分区来极大地促进。
某些查询可以在数据满足给定
WHERE
子句的情况下进行优化,因为这些数据可能仅存储在一个或多个分区中,这会自动将任何剩余的分区排除在搜索范围之外。由于分区可以在创建分区表后进行更改,因此您可以重新组织数据以增强可能在最初设置分区方案时使用不频繁的频繁查询。这种排除不匹配分区(以及它们包含的任何行)的能力通常被称为 分区修剪。有关更多信息,请参阅 第 26.4 节,“分区修剪”。此外,MySQL 支持对查询进行显式分区选择。例如,
SELECT * FROM t PARTITION (p0,p1) WHERE c < 5
仅选择p0
和p1
分区中与WHERE
条件匹配的行。在这种情况下,MySQL 不会检查表t
的任何其他分区;当您已经知道要检查哪个分区或多个分区时,这可以极大地加快查询速度。分区选择也支持数据修改语句DELETE
、INSERT
、REPLACE
、UPDATE
以及LOAD DATA
、LOAD XML
。有关更多信息和示例,请参阅这些语句的描述。