22.2.4 HASH 分区

HASH分区主要用于确保在 sched 数量的分区之间均匀分布数据。对于范围或列 table 分区,必须明确指定将给定列值或一组列值存储在哪个分区中;使用散列分区,MySQL 会为您解决这一问题,您只需要基于要散列的列值和要划分的分区 table 的分区数来指定列值或 table 达式。

要使用HASH分区对 table 进行分区,必须在CREATE TABLE语句后附加PARTITION BY HASH (expr)子句,其中* expr 是返回整数的 table 达式。这可以只是列的名称,该列的类型是 MySQL 的整数类型之一。此外,您很可能希望在此之后加上PARTITIONS num,其中 num *是一个正整数,table 示要将 table 划分为的分区数。

Note

为简单起见,以下示例中的 table 不使用任何键。您应该注意,如果 table 具有任何唯一键,则该 table 的分区 table 达式中使用的每一列都必须是每个唯一键(包括主键)的一部分。有关更多信息,请参见第 22.6.1 节“分区键,主键和唯一键”

以下语句创建一个在store_id列上使用哈希的 table,并分为 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;

如果不包括PARTITIONS子句,则分区数默认为1

使用PARTITIONS关键字后不带数字会导致语法错误。

您还可以使用返回* expr *的整数的 SQLtable 达式。例如,您可能想根据雇用员工的年份进行划分。可以按如下所示完成:

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;
  • expr *必须返回非恒定,非随机的整数值(换句话说,它应该是可变的但是确定性的),并且不得包含第 22.6 节“分区的限制和限制”中描述的任何禁止的构造。您还应该记住,每次插入或更新(或可能删除)一行时,都会对该 table 达式进行求值;这意味着非常复杂的 table 达式可能会引起性能问题,尤其是在执行一次影响很多行的操作(例如批处理插入)时。

最有效的散列函数是对单个 table 列进行操作的函数,其值与列值一致地增加或减少,因为这允许对分区范围进行“修剪”。也就是说,table 达式随着 table 达式所基于的列的值变化的越紧密,MySQL 可以更有效地将 table 达式用于哈希分区。

例如,在date_col是类型DATE的列的情况下,则 table 达式TO_DAYS(date_col)date_col的值而直接变化,因为对于date_col的值的每次更改,table 达式的值都以一致的方式变化。table 达式YEAR(date_col)相对于date_col的方差并不像TO_DAYS(date_col)的方差那么直接,因为date_col中的每种可能变化都不会产生YEAR(date_col)的等效变化。即便如此,YEAR(date_col)还是适用于散列函数的很好的候选者,因为YEAR(date_col)date_col的一部分而直接变化,并且date_col没有可能的变化而导致YEAR(date_col)的变化不成比例。

相比之下,假设您有一个名为int_col的列,其类型为INT。现在考虑 table 达式战俘(5-int_col,3)6。对于哈希函数而言,这将是一个糟糕的选择,因为不能保证int_col的值更改会导致 table 达式值的比例更改。将int_col的值更改给定的数量会导致 table 达式的值产生很大不同的变化。例如,将int_col5更改为6会使 table 达式的值改变-1,但是将int_col的值从6更改为7会导致 table 达式的值改变-7

换句话说,列值与 table 达式的值的曲线越接近方程y=cx所跟踪的直线,其中* c *是一些非零常数,则 table 达式越适合于散列。这与以下事实有关:table 达式越非线性,它倾向于产生的分区之间的数据分布就越不均匀。

从理论上讲,也可以对涉及多个列值的 table 达式进行修剪,但是要确定哪种 table 达式合适则可能非常困难且耗时。因此,不特别推荐使用涉及多列的哈希 table 达式。

当使用PARTITION BY HASH时,MySQL 根据 table 达式结果的模数来确定要使用* num 的哪个分区。换句话说,对于给定的 table 达式 expr ,存储记录的分区是分区号 N *,其中N = MOD(expr, num)。假设 tablet1的定义如下,因此它具有 4 个分区:

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

如果将记录插入到col3值为'2005-09-15't1中,则存储记录的分区将确定如下:

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

MySQL 5.7 还支持称为线性哈希的HASH分区变体,该变体采用更复杂的算法来确定插入分区 table 中的新行的位置。有关此算法的说明,请参见第 22.2.4.1 节“线性哈希分区”

每次插入或更新记录时,都会评估用户提供的 table 达式。当删除记录时,还可以根据情况对它进行评估。