介绍

基于给定的分区个数,将数据分配到不同的分区,hash分区只能针对整数进行hash,对于非整形的字段只能通过表达式将其转换成整数。表达式可以是mysql中任意有效的函数或者表达式,对于非整形的hash往表插入数据的过程中会多一步表达式的计算操作,所以不建议使用复杂的表达式这样会影响性能。

mysql支持两种hash分区,常规hash(hash)和线性hash(linear hash)。

一、常规hash

常规hash是基于分区个数的取模(%)运算。根据余数插入到指定的分区

create table tbhash (
    id int not null,
    store_id int
)
partition by hash(store_id)
partitions 4
;
alter table tbhash add index ix_store_id(store_id);
insert into tbhash() values(1,100),(1,101),(2,102),(3,103),(4,104);

select partition_name,partition_method,partition_expression,partition_description,table_rows,subpartition_name,subpartition_method,subpartition_expression 
from information_schema.partitions where table_schema=schema() and table_name='tbhash';

其中100,104对4取模是0所以这两条数据被分配到了p0分区。

2.时间类型字段

create table employees (
    id int not null,
    hired date not null default '1970-01-01',
)
partition by hash( year(hired) )
partitions 4;

常规hash的分区非常的简便,通过取模的方式可以让数据非常平均的分布每一个分区,但是由于分区在创建表的时候已经固定了。如果新增或者收缩分区的数据迁移比较大。

二、线性hash(linear hash)

linear hash和hash的唯一区别就是partition by linear hash

create table tblinhash (
    id int not null,
    hired date not null default '1970-01-01'
)
partition by linear hash( year(hired) )
partitions 6;

线性hash的计算原理如下:

假设分区个数num=6,n表示数据最终存储的分区

sep1:v = power(2, ceiling(log(2, num))),log()是计算num以2为底的对数,ceiling()是向上取整,power()是取2的次方值;如果num的值是2的倍数那么这个表达式计算出来的结果不变。

v=power(2,ceiling(log(2,6)))

v=power(2,3)

v=8

sep2:n=values&(v-1);&位与运算,将两个值都转换成2进行求与运算,当都为1才为1;当num是2的倍数时由于v计算出来的结果不变,这时values&(v-1)=mod(values/num)和时间hash取模算出的结果是一致的,这时特殊情况只有当分区是2的倍数才是这种 情况。values是year(hired)的值

sep3:while n>=num

sep3-1:n=n& (ceil(v/ 2)- 1)

例如:

1.当插入的值是’2003-04-14’时

    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),n不大于num所以存储在第3分区,注意这里的3指的是p3,分区号是从p0开始。

2.当插入的值是‘1998-10-19’

v = power(2, ceiling( log(2,6) )) = 8

n = year(‘1998-10-19’) & (8-1)

= 1998 & 7

= 6

(6 >= 6 is true: additional step required),由于n>=num所以要进行第三步操作

n=n&(ceiling(8/2)-1)

=6&3

=2

(2>=6is false:recored in partition #2),由于2不大于6所以存储在第2个分区,注意这里的3指的是p2,分区号是从p0开始。

insert into tblinhash() values(1,'2003-04-14'),(2,'1998-10-19');
select partition_name,partition_method,partition_expression,partition_description,table_rows,subpartition_name,subpartition_method,subpartition_expression 
from information_schema.partitions where table_schema=schema() and table_name='tblinhash';

explain select * from tblinhash where hired='2003-04-14';

三、分区管理

常规hash和线性hash的增加收缩分区的原理是一样的。增加和收缩分区后原来的数据会根据现有的分区数量重新分布。hash分区不能删除分区,所以不能使用drop partition操作进行分区删除操作;

只能通过alter table … coalesce partition num来合并分区,这里的num是减去的分区数量;

可以通过alter table … add partition partitions num来增加分区,这里是null是在原先基础上再增加的分区数量。

1.合并分区

减去3个分区

alter table tblinhash coalesce partition 3;
select partition_name,partition_method,partition_expression,partition_description,table_rows,subpartition_name,subpartition_method,subpartition_expression 
from information_schema.partitions where table_schema=schema() and table_name='tblinhash';

注意:减去两个分区后,数据根据现有的分区进行了重新的分布,以’2003-04-14’为例:power(2, ceiling( log(2,3) ))=4,2003&(4-1)=3,3>=3,3&(ceiling(3/2)-1)=1,所以现在的’2003-04-14’这条记录由原来的p3变成了p1

2.增加分区

增加4个分区

alter table tblinhash add partition partitions 4;
select partition_name,partition_method,partition_expression,partition_description,table_rows,subpartition_name,subpartition_method,subpartition_expression 
from information_schema.partitions where table_schema=schema() and table_name='tblinhash';

当在3个分区的基础上增加4个分区后,‘2003-04-14’由原来的p1变成了p3,而另一条记录由原来的p2变成了p6

四、移除表的分区

alter table tablename
remove partitioning ;

注意:使用remove移除分区是仅仅移除分区的定义,并不会删除数据和drop partition不一样,后者会连同数据一起删除

分区系列文章:

range分区:

column分区:

list分区:

hash分区:

key分区:

子分区:

指定各分区路径:

分区索引以及分区介绍总结:

总结

常规hash的数据分布更加均匀一些,也便于理解;目前还没有彻底理解为什么线性hash在收缩和增加分区时处理的速度会更快,同时线性hash的数据分布不均匀。

到此这篇关于mysql分区之hash分区的文章就介绍到这了,更多相关mysql hash分区内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!