使用 HASH
进行分区主要用于确保数据在预定数量的分区之间均匀分布。对于范围或列表分区,您必须明确指定应在哪个分区中存储给定的列值或列值集;对于哈希分区,此决定由系统自动完成,您只需指定要进行哈希处理的列值或基于列值的表达式,以及要将分区表划分的目标分区数。
要使用 HASH
分区对表进行分区,需要在 CREATE TABLE
语句后附加一个 PARTITION BY HASH (
子句,其中 expr
)expr
是一个返回整数的表达式。这可以简单地是其类型为 MySQL 整数类型之一的列的名称。此外,您很可能希望在其后加上 PARTITIONS
,其中 num
num
是一个正整数,表示要将表划分的目标分区数。
为简单起见,以下示例中的表不使用任何键。您应该注意,如果表有任何唯一键,则此表的分区表达式中使用的每一列都必须是每个唯一键的一部分,包括主键。有关更多信息,请参阅 第 26.6.1 节“分区键、主键和唯一键”。
以下语句创建一个表,该表在 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;
如果您不包含 PARTITIONS
子句,则分区数默认为 1
;使用 PARTITIONS
关键字而不带后面的数字会导致语法错误。
您还可以使用返回 expr
整数的 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;
expr
必须返回非恒定、非随机的整数值(换句话说,它应该是可变的但确定的),并且不得包含 第 26.6 节“分区的限制” 中所述的任何禁止的构造。您还应该记住,每次插入或更新(或可能删除)行时都会计算此表达式;这意味着非常复杂的表达式可能会导致性能问题,尤其是在执行一次影响大量行的操作(例如批量插入)时。
最有效的哈希函数是对单个表列进行操作的函数,其值随列值一致地增加或减少,因为这允许对分区范围进行““修剪””。也就是说,表达式的变化与它所基于的列的值的变化越接近,MySQL 就越能有效地使用该表达式进行哈希分区。
例如,其中 date_col
是类型为 DATE
的列,则表达式 TO_DAYS(date_col)
被认为与 date_col
的值直接相关,因为对于 date_col
值的每次更改,表达式的值都会以一致的方式更改。表达式 YEAR(date_col)
相对于 date_col
的变化不如 TO_DAYS(date_col)
那么直接,因为并非 date_col
的所有可能变化都会在 YEAR(date_col)
中产生等效的变化。即便如此,YEAR(date_col)
也是哈希函数的良好候选者,因为它直接随 date_col
的一部分而变化,并且 date_col
中不可能发生导致 YEAR(date_col)
中不成比例变化的变化。
相比之下,假设您有一个名为 int_col
的列,其类型为 INT
。现在考虑表达式 POW(5-int_col,3) + 6
。这将是哈希函数的一个糟糕选择,因为 int_col
值的变化不能保证在表达式值中产生成比例的变化。将 int_col
的值更改给定量可能会在表达式值中产生 widely differing changes。例如,将 int_col
从 5
更改为 6
会导致表达式值更改 -1
,但将 int_col
的值从 6
更改为 7
会导致表达式值更改 -7
。
换句话说,列值与表达式值的关系图越接近于方程 y=
(其中 c
xc
是某个非零常数)绘制的直线,则该表达式越适合于哈希。这与以下事实有关:表达式越是非线性,它在分区之间产生的数据分布往往越不均匀。
从理论上讲,对于涉及多个列值的表达式,修剪也是可能的,但确定哪些表达式合适可能非常困难且耗时。因此,不特别建议使用涉及多列的哈希表达式。
使用 PARTITION BY HASH
时,存储引擎会根据表达式结果的模数确定使用 num
个分区中的哪个分区。换句话说,对于给定的表达式 expr
,存储记录的分区是分区号 N
,其中
。假设表 N
= MOD(expr
, num
)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 9.0 还支持 HASH
分区的一种变体,称为 线性哈希,它采用更复杂的算法来确定插入到分区表中的新行的放置。有关此算法的描述,请参阅 第 26.2.4.1 节“LINEAR HASH 分区”。
每次插入或更新记录时,都会计算用户提供的表达式。根据情况,在删除记录时也可能会对其进行计算。