### 24.2.4 哈希分区

[24.2.4.1 线性哈希分区](partitioning-linear-hash.html)

[](<>)[](<>)

分区依据`哈希`主要用于确保数据在预定数量的分区之间的均匀分布。对于范围或列表分区，您必须明确指定给定列值或列值集应存储在哪个分区中；使用散列分区，这个决定由您负责，您只需要根据要散列的列值和分区表要划分的分区数来指定列值或表达式。

使用分区表`哈希`分区，有必要追加到[`创建表`](create-table.html)声明一`按哈希分区 (*`表达式`*)`子句，其中*`表达式`*是一个返回整数的表达式。这可以只是类型为 MySQL 整数类型之一的列的名称。此外，您很可能希望使用`分区 *`数`*`， 在哪里*`数`*是一个正整数，表示表要划分的分区数。

笔记

为简单起见，以下示例中的表不使用任何键。您应该知道，如果一个表有任何唯一键，则该表的分区表达式中使用的每一列都必须是每个唯一键的一部分，包括主键。看[第 24.6.1 节，“分区键、主键和唯一键”](partitioning-limitations-partitioning-keys-unique-keys.html)， 了解更多信息。

以下语句创建一个使用散列的表`store_id`列并分为4个分区：

```
CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY HASH(store_id)
PARTITIONS 4;
```

如果您不包括`分区`子句，分区数默认为`1`;使用`分区`后面没有数字的关键字会导致语法错误。

[](<>)

您还可以使用返回整数的 SQL 表达式*`表达式`*.例如，您可能希望根据员工受雇的年份进行分区。这可以如下所示完成：

```
CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY HASH( YEAR(hired) )
PARTITIONS 4;
```

*`表达式`*必须返回一个非常量、非随机的整数值（换句话说，它应该是可变但确定的），并且不得包含任何禁止的构造，如[第 24.6 节，“分区的限制和限制”](partitioning-limitations.html).您还应该记住，每次插入或更新（或可能删除）行时都会评估此表达式；这意味着非常复杂的表达式可能会导致性能问题，尤其是在执行一次影响大量行的操作（例如批量插入）时。

最有效的散列函数是对单个表列进行操作并且其值随列值一致增加或减少的散列函数，因为这允许对分区范围进行“修剪”。也就是说，表达式越接近于它所基于的列的值，MySQL 可以更有效地使用该表达式进行哈希分区。

例如，在哪里`date_col`是类型的列[`日期`](datetime.html), 那么表达式[`TO_DAYS(date_col)`](date-and-time-functions.html#function_to-days)据说直接随值变化`date_col`，因为对于价值的每一次变化`date_col`，表达式的值以一致的方式变化。表达式的方差[`年份（date_col）`](date-and-time-functions.html#function_year)关于`date_col`不如直接[`TO_DAYS(date_col)`](date-and-time-functions.html#function_to-days), 因为不是所有可能的变化`date_col`产生等效的变化[`年份（date_col）`](date-and-time-functions.html#function_year).即使是这样，[`年份（date_col）`](date-and-time-functions.html#function_year)是散列函数的一个很好的候选者，因为它直接随`date_col`并且没有可能的变化`date_col`会产生不成比例的变化[`年份（date_col）`](date-and-time-functions.html#function_year).

相比之下，假设您有一个名为`int_col`谁的类型是[`INT`](integer-types.html).现在考虑表达式[`POW(5-int_col,3) + 6`](mathematical-functions.html#function_pow).这对于散列函数来说是一个糟糕的选择，因为`int_col`不保证会在表达式的值中产生成比例的变化。改变价值`int_col`通过给定的数量可以产生表达式值的大不相同的变化。例如，改变`int_col`从`5`到`6`产生变化`-1`在表达式的值中，但改变了`int_col`从`6`到`7`产生变化`-7`在表达式值中。

换句话说，列值与表达式值的关系图越接近直线，如等式所示`y=*`c`*x`在哪里*`c`*是一些非零常数，表达式越适合散列。这与以下事实有关：表达式的非线性程度越高，它倾向于产生的分区之间的数据分布就越不均匀。

理论上，对于涉及多个列值的表达式也可以进行修剪，但确定哪些表达式是合适的可能非常困难且耗时。因此，不特别推荐使用涉及多列的散列表达式。

什么时候`哈希分区`使用时，存储引擎确定哪个分区*`数`*基于表达式结果的模数使用的分区。换句话说，对于给定的表达式*`表达式`*，存储记录的分区为分区号*`ñ`*， 在哪里`*`ñ`* = 国防部（*`表达式`*, *`数`*)`.假设那张桌子`t1`定义如下，使其有4个分区：

```
CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE)
    PARTITION BY HASH( YEAR(col3) )
    PARTITIONS 4;
```

如果将记录插入`t1`谁的`col3`值为`'2005-09-15'`，那么存储它的分区确定如下：

```
MOD(YEAR('2005-09-01'),4)
=  MOD(2005,4)
=  1
```

MySQL 8.0 还支持`哈希`分区称为线性散列，它采用更复杂的算法来确定插入分区表的新行的位置。看[第 24.2.4.1 节，“线性哈希分区”](partitioning-linear-hash.html)，用于描述该算法。

每次插入或更新记录时都会评估用户提供的表达式。根据具体情况，也可以在删除记录时对其进行评估。
