本节提供有关 MySQL 9.0 中分区的概念性概述。
有关分区限制和功能限制的信息,请参阅 第 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 9.0 不支持 垂直分区,其中表的不同列分配给不同的物理分区。目前没有计划在 MySQL 中引入垂直分区。
要创建分区表,您必须使用支持它们的存储引擎。在 MySQL 9.0 中,同一分区表的全部分区必须使用相同的存储引擎。但是,没有任何东西可以阻止您对同一 MySQL 服务器上甚至同一数据库中的不同分区表使用不同的存储引擎。
在 MySQL 9.0 中,唯一支持分区的存储引擎是 InnoDB
和 NDB
。分区不能与不支持它的存储引擎一起使用;这些引擎包括 MyISAM
、MERGE
、CSV
和 FEDERATED
存储引擎。
通过 KEY
或 LINEAR KEY
进行分区是 NDB
可行的,但其他类型的用户定义分区不支持使用此存储引擎的表。此外,使用用户定义分区的 NDB
表必须具有明确的主键,并且表分区表达式中引用的任何列都必须是主键的一部分。但是,如果在用于创建或修改用户分区 NDB
表的 CREATE TABLE
或 ALTER TABLE
语句的 PARTITION BY KEY
或 PARTITION BY LINEAR KEY
子句中未列出任何列,则该表不需要具有明确的主键。有关更多信息,请参阅 第 25.2.7.1 节,“NDB Cluster 中的 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 9.0 中,此选项没有任何作用。
除非另有说明,否则本讨论中的其余示例假设 default_storage_engine
为 InnoDB
。
分区适用于表的全部数据和索引;您不能只分区数据而不分区索引,反之亦然,也不能只分区表的一部分。
每个分区的的数据和索引可以使用 CREATE TABLE
语句的 PARTITION
子句中的 DATA DIRECTORY
和 INDEX DIRECTORY
选项分配到特定目录。
只有 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 Cluster 表,从而允许存储更多散列索引。有关更多信息,请参阅 DataMemory
数据节点配置参数的文档以及 第 25.2.2 节,“NDB Cluster 节点、节点组、片段副本和分区”。
以下是分区的优势:
分区使您可以在一张表中存储比单个磁盘或文件系统分区上能容纳的更多数据。
通常可以轻松地从分区表中删除不再有用的数据,方法是删除仅包含该数据的分区(或分区)。相反,在某些情况下,添加新数据可以大大简化,方法是添加一个或多个用于专门存储该数据的新分区。
由于满足给定
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
。有关更多信息和示例,请参阅这些语句的描述。