Mysql --分区表(6)Hash分区

HASH分区

HASH分区主要用来分散热点读,确保数据在预先确定个数的分区中尽可能平均分布。对一个表执行HASH分区时,MySQL会对分区键应用一个散列函数,以此确定数据应当放在N个分区中的哪个分区
MySQL支持两种HASH分区,常规HASH分区和线性HASH分区(LINEAR HASH);常规HASH使用的是取模算法,线性HASH分区使用的是一个线性的2的幂的运算法则

使用PARTITION BY HASH(expr)创建hash分区表,expr需要返回一个整数

下面的例子中创建了一个以store_id为分区键的hash分区表,如果你没有写partitions子句,那么默认为partitions 1

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;

你也可以使用一个返回整型的表达是作为分区键

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必须返回一个非恒定的,非随机整数值(换句话说,应该是变化,但又是确定的)
同时应当注意的是,该表达式在每次insert update时都会被执行从而决定将数据放入哪个分区,所以如该表达式的性能低下,会影响整个分区表的性能
MySQL也不推荐使用涉及多列的hash表达式

常规HASH分区方式看上去挺不错的,通过取模的方式将数据尽可能的平均分布在每个分区中,让每个分区管理的数据都减少了,提高了查询的效率;课时当我们需要增加分区或者合并分区的时候,问题就出现了。假设原来是5个常规HASH分区,现在需要新增一个常规HASH分区,原来的取模算法是MOD(expr,5),根据余数0-4分布在五个分区中,现在新增一个分区,取模算法编程MOD(expr,6),根据余数0-5分布在6个分区中,原来5个分区中的数据大部分需要通过重新计算重新分区。
常规HASH分区在分区管理上带来的代价太大了,不适合需要灵活变动的需求。为了降低分区管理上的代价,MySQL提供了线性HASH分区,分区函数是一个线性的2的幂的运算法则

create table normal_hash(
    id int 
)
partition by hash(id)
partitions 5; 

delimiter $$
create procedure normal_insert()
begin
	declare line int default 0;
	while line<1000
	do
		insert into normal_hash values(line);
		set line=line+1;
	end while;
end$$

call normal_insert();

mysql> select 
    ->   partition_name part,  
    ->   partition_expression expr,  
    ->   partition_description descr,  
    ->   table_rows  
    -> from information_schema.partitions  where 
    ->   table_schema = schema()  
    ->   and table_name='normal_hash';
+------+------+-------+------------+
| part | expr | descr | table_rows |
+------+------+-------+------------+
| p0   | id   | NULL  |        200 |
| p1   | id   | NULL  |        200 |
| p2   | id   | NULL  |        200 |
| p3   | id   | NULL  |        200 |
| p4   | id   | NULL  |        200 |
+------+------+-------+------------+
线性hash分区

线性HASH分区和常规HASH分区在语法上的唯一区别是在”PARTITION BY”子句中添加LINEAR关键字

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 LINEAR HASH( YEAR(hired) )
PARTITIONS 4;

使用线性HASH是,指定记录保存在哪个分区是可以计算出来的,假设将要保存的记录的分区编号设为N,num是一个非负整数,表示分割成分区的数量,那么N可以通过以下算法得到

首先,找到一个大于等于num的2的幂,这个值设为V,V可以通过下面的公式得到
V = POWER(2, CEILING(LOG(2, num)))
例如,刚才创建的employees表预先设定了4个分区,num=4
V = POWER(2, CEILING(LOG(2, 4)))
= POWER(2, CEILING(2))
= POWER(2, 2)
= 4

其次,设置N = F(column_list) & (v-1)
例如,我们刚才计算出V=4,现在计算stroe_id=234对于的值
N = F(column_list) & (v-1)
= 234 & (4-1)
= 2

当 N>=num
设置V=Ceiling(v/2),这时N=N & (V-1)
对于store_id=234这条记录,由于N=2<4;所以直接就能够判断这条记录会被存储在第二个分区中

V = POWER(2, CEILING( LOG(2,6) )) = 8
N = YEAR('2003-04-14') & (8 - 1)
   = 2003 & 7
   = 3

(3 >= 6 is FALSE: record stored in partition #3)


V = 8
N = YEAR('1998-10-19') & (8-1)
  = 1998 & 7
  = 6

(6 >= 6 is TRUE: additional step required)

N = 6 & CEILING(8 / 2)
  = 6 & 3
  = 2

(2 >= 6 is FALSE: record stored in partition #2)

有意思的是,当线性HASH分区的个数是2的N次冥时,线性HASH分区的结果和常规HASH分区的结果是一致的

线性HASH分去的有点事,在分区维护(包括增加、删除、合并、拆分分区)时,MySQL能够处理的更加迅速;缺点是,对比常规HASH分区(取模)的时候,线性HASH各个分区之间数据的分布不太均衡

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值