## 24.1 MySQL 中的分区概述

[](<>)

本节提供 MySQL 8.0 中分区的概念性概述。

有关分区限制和功能限制的信息，请参阅[第 24.6 节，“分区的限制和限制”](partitioning-limitations.html).

SQL 标准在数据存储的物理方面没有提供太多指导。SQL 语言本身旨在独立于它所使用的架构、表、行或列下的任何数据结构或媒体而工作。尽管如此，大多数先进的数据库管理系统已经发展了一些确定用于存储特定数据块的物理位置的方法，这些数据包括文件系统、硬件甚至两者。在 MySQL 中，`InnoDB`存储引擎长期以来一直支持表空间的概念（参见[第 15.6.3 节，“表空间”](innodb-tablespace.html))，并且 MySQL 服务器，即使在引入分区之前，也可以配置为使用不同的物理目录来存储不同的数据库（参见[第 8.12.2 节，“使用符号链接”](symbolic-links.html)，以了解如何完成此操作）。

分区使这个概念更进了一步，使您能够根据您可以根据需要在很大程度上设置的规则在文件系统中分布各个表的部分。实际上，表的不同部分作为单独的表存储在不同的位置。完成数据划分的用户选择规则称为分区函数，在 MySQL 中可以是模数、与一组范围或值列表的简单匹配、内部散列函数或线性散列函数。该函数根据用户指定的分区类型进行选择，并将用户提供的表达式的值作为其参数。此表达式可以是一个列值、作用于一个或多个列值的函数或一组一个或多个列值，具体取决于所使用的分区类型。

如果是`范围`,`列表`， 和[`线性`] `哈希`分区时，将分区列的值传递给分区函数，该函数返回一个整数值，表示应存储该特定记录的分区号。此函数必须是非常量且非随机的。它可能不包含任何查询，但可以使用在 MySQL 中有效的 SQL 表达式，只要该表达式返回`空值`或整数*`间隔`*这样

```
-MAXVALUE <= intval <= MAXVALUE
```

(`最大值`用于表示所讨论的整数类型的最小上限。`-MAXVALUE`代表最大的下限。）

为了[`线性`] `钥匙`,`范围列`， 和`列出列`分区，分区表达式由一个或多个列的列表组成。

为了[`线性`] `钥匙`分区，分区功能由 MySQL 提供。

有关允许的分区列类型和分区函数的更多信息，请参阅[第 24.2 节，“分区类型”](partitioning-types.html)， 也[第 13.1.20 节，“CREATE TABLE 语句”](create-table.html)，它提供了分区语法描述和其他示例。有关分区函数限制的信息，请参阅[第 24.6.3 节，“与函数相关的分区限制”](partitioning-limitations-functions.html).

这被称为水平分区——也就是说，表的不同行可以分配给不同的物理分区。MySQL 8.0 不支持垂直分区，其中一个表的不同列被分配到不同的物理分区。目前没有计划将垂直分区引入 MySQL。

要创建分区表，您必须使用支持它们的存储引擎。在 MySQL 8.0 中，同一个分区表的所有分区必须使用相同的存储引擎。但是，没有什么可以阻止您对同一 MySQL 服务器甚至同一数据库中的不同分区表使用不同的存储引擎。

在 MySQL 8.0 中，唯一支持分区的存储引擎是`InnoDB`和[`新开发银行`](mysql-cluster.html).不支持分区的存储引擎不能使用分区；这些包括`MyISAM`,`合并`,`CSV`， 和`联邦`存储引擎。

分区依据`钥匙`要么`线性键`是可能的[`新开发银行`](mysql-cluster.html)，但使用此存储引擎的表不支持其他类型的用户定义分区。此外，一个[`新开发银行`](mysql-cluster.html)使用用户定义分区的表必须具有显式主键，并且表的分区表达式中引用的任何列都必须是主键的一部分。但是，如果没有列在`按键分区`要么`线性键分区`的条款[`创建表`](create-table.html)要么[`更改表`](alter-table-partition-operations.html)用于创建或修改用户分区的语句[`新开发银行`](mysql-cluster.html)表，则该表不需要具有显式主键。有关详细信息，请参阅[第 23.2.7.1 节，“NDB Cluster 中不符合 SQL 语法”](mysql-cluster-limitations-syntax.html).

创建分区表时，与创建任何其他表时一样使用默认存储引擎；要覆盖此行为，只需使用`[存储] 引擎`选项就像未分区的表一样。目标存储引擎必须提供本机分区支持，否则语句将失败。你应该记住`[存储] 引擎`（和其他表格选项）需要列出*前*任何分区选项都用于[`创建表`](create-table.html)陈述。这个例子展示了如何创建一个按散列划分为 6 个分区并使用`InnoDB`存储引擎（无论[`default_storage_engine`](server-system-variables.html#sysvar_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;
```

每个`划分`子句可以包括`[存储] 引擎`选项，但在 MySQL 8.0 中这没有效果。

除非另有说明，否则本讨论中的其余示例均假定[`default_storage_engine`](server-system-variables.html#sysvar_default_storage_engine)是`InnoDB`.

重要的

分区适用于表的所有数据和索引；您不能只分区数据而不分区索引，反之亦然，也不能只分区表的一部分。

每个分区的数据和索引可以使用`数据目录`和`索引目录`的选项`划分`的条款[`创建表`](create-table.html)用于创建分区表的语句。

只有`数据目录`单个分区和子分区支持选项`InnoDB`表。从 MySQL 8.0.21 开始，在 a 中指定的目录`数据目录`条款必须知道`InnoDB`.有关详细信息，请参阅[使用数据目录子句](innodb-create-table-external.html#innodb-create-table-external-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`和`英国`没有共同的列，没有可用于分区表达式的列。在这种情况下可能的解决方法包括添加`姓名`列到表的主键，添加`id`列到`英国`，或者干脆完全删除唯一键。看[第 24.6.1 节，“分区键、主键和唯一键”](partitioning-limitations-partitioning-keys-unique-keys.html)， 了解更多信息。

此外，`MAX_ROWS`和`MIN_ROWS`可用于分别确定可以存储在每个分区中的最大和最小行数。看[第 24.3 节，“分区管理”](partitioning-management.html), 有关这些选项的更多信息。

[](<>)

这`MAX_ROWS`选项对于创建具有额外分区的 NDB Cluster 表也很有用，从而允许存储更多的哈希索引。请参阅文档[`数据存储器`](mysql-cluster-ndbd-definition.html#ndbparam-ndbd-datamemory)数据节点配置参数，以及[第 23.2.2 节，“NDB 集群节点、节点组、片段副本和分区”](mysql-cluster-nodes-groups.html)， 了解更多信息。

[](<>)

这里列出了分区的一些优点：

-   分区可以在一个表中存储比单个磁盘或文件系统分区上更多的数据。

-   通过删除仅包含该数据的分区（或多个分区），通常可以轻松地从分区表中删除失去其用途的数据。相反，在某些情况下，通过添加一个或多个新分区来专门存储该数据，可以极大地促进添加新数据的过程。

-   由于数据满足给定的事实，一些查询可以得到极大的优化`在哪里`子句只能存储在一个或多个分区上，这会自动从搜索中排除任何剩余的分区。因为在创建分区表后可以更改分区，所以您可以重新组织数据以增强在首次设置分区方案时可能不经常使用的频繁查询。这种排除不匹配分区（以及它们包含的任何行）的能力通常称为分区修剪。有关详细信息，请参阅[第 24.4 节，“分区修剪”](partitioning-pruning.html).

    此外，MySQL 支持查询的显式分区选择。例如，[`SELECT * FROM t PARTITION (p0,p1) WHERE c < 5`](select.html)仅选择分区中的那些行`p0`和`p1`匹配的`在哪里`健康）状况。在这种情况下，MySQL 不会检查表的任何其他分区`吨`;当您已经知道要检查哪个或哪些分区时，这可以大大加快查询速度。数据修改语句也支持分区选择[`删除`](delete.html),[`插入`](insert.html),[`代替`](replace.html),[`更新`](update.html)， 和[`加载数据`](load-data.html),[`加载 XML`](load-xml.html).有关更多信息和示例，请参阅这些语句的描述。
