1.对表进行分区的原因和场景
改善大表、具有各种访问模式的表的可伸缩性、可管理性,提高效率
优点:
与单个磁盘或文件系统分区相比,可存储更多的数据,2T→16T;
通过删除与增加有关数据的分区,很容易删除或增加那些数据;
一些查询能得到优化;
通过跨多个磁盘甚至服务器分散查询,获得更大的查询吞吐量;
MySQL5.5之后支持所有函数的分区优化,之前只有两个聚合函数可以使用在分区表中。
2.分区类型
基本分区类型:
RANGE分区:基于属于一个给定连续区间的列值,把多行分配给分区
LIST分区:类似于按RANGE分区,区别是LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择
HASH分区:基于用户定义的表达式的返回值来进行选择分区,该表达式使用将要插入到表中的这些行的列值进行计算,这个函数可以包含MySQL中有效的、产生非负整数值的任何表达式
KEY分区:类似于HASH分区,区别在于KEY分区只支持计算一列或多列
3.RANGE分区
改成分区表:
alter table titles
partition by range (year(from_date)) #基于from_date列中的年份来分区
(
partition p01 values less than (1985),
partition p02 values less than (1986),
partition p03 values less than (1987),
partition p04 values less than (1988),
partition p15 values less than (1999),
partition p16 values less than (MAXVALUE)
);
直接创建分区表:
create table t1 (id int ,name varchar(20), age int)
partition by range(age)
(
partition p01 values less than (10), #不包括10,即<10
partition p02 values less than (20), #不包括20,即≥10且<20
partition p03 values less than (30),
partition p04 values less than (maxvalue)
);
注:分区的名称是不区分大小写的
分区表的文件也有所不同,frm和普通表一样是表结构信息
.par文件是分区信息
.ibd是每个分区的数据信息,有多个
4.LIST分区
create table t2 (id int, cid int ,name varchar(20),pos_date datetime)
partition by list (cid)
(
partition p01 values in (1,3,5),
partition p02 values in (2,8,9),
partition p03 values in (4,6,7)
);
5.HASH分区
具体算法较为复杂,要看官方文档或源码
但是使用起来很方便:
create table t3(id int,cid int,name varchar(20),pos_date datetime)
parttion by hash(cid)
partitions 4;
另有LINEAR HASH分区
优点在于增加、删除、合并和拆分分区将变得更加快捷,有利于处理含有极大量(1T)数据的表
缺点在于数据分布可能不够均匀,容易产生hotspot nodes
语法和普通哈希分区区别不大,例:
create table t3(id int,cid int,name varchar(20),pos_date datetime)
parttion by linear hash(cid)
partitions 4;
6.KEY分区
使用几率不大
create table t4(id int,cid int,name varchar(20),pos_date datetime)
parttion by linear key(cid)
partitions 4;
7.多列分区
在5.5之后可以依据多个字段进行分区
create table t5 (a int , b int , c int)
partition by range columns(a,b)
(
partition p01 values less than (10,10),
partition p02 values less than (10,20), #前一个是a列,后一个是b列
partition p03 values less than (10,30),
partition p04 values less than (10,maxvalue),
partition p05 values less than (maxvalue,maxvalue)
);
8.子分区
子分区是分区表中每个分区的再次分割,
子分区可以用于特别大的表,在多个磁盘间分配数据和索引
create table t6(id INT, udate DATE)
partition by range (YEAR(udate))
subpartition by HASH(TO_DAYS(udate))
subpartitions 2
(
partition p0 VALUES LESS THAN (1990),
partition p1 VALUES LESS THAN (2000),
partition p2 VALUES LESS THAN (maxvalue)
);
将子分区保存在不同的存储上,优化I/O性能
是互联网公司非常常见的操作
create tabl ts (id int ,udate DATE)
partition by range(YEAR(udate))
subpartition by HASH(TO_DAYS(udate))
(
partition p0 values less than (1990)
(
subpartition s0
DATA DIRECTORY = '/disk0/data'
INDEX DIRECTORY = 'disk0/idx',
subpartition s1
DATA DIRECTORY = '/disk1/data'
INDEX DIRECTORY = 'disk1/idx'
),
partition p1 values less than (2000)
(
subpartition s2
DATA DIRECTORY = '/disk2/data'
INDEX DIRECTORY = 'disk2/idx',
subpartition s3
DATA DIRECTORY = '/disk3/data'
INDEX DIRECTORY = 'disk3/idx'
)
);
记得不同目录都要给OS层mysql用户授权
此时能看到有isl文件,是个文本文件,打开后是一个路径,保存了ibd文件的位置
我们也可以修改这个isl文件来修改目录位置;
提醒:
每个分区必须有相同数量的子分区;
假设一个分区定义了子分区,那么其他分区也必须定义子分区;
子分区名称不能重复;
9.分区管理
9.1简单修改分区
使用alter语句,效果和先删除原表再按新的分区方式重新建表效果相同
也可以用在改变分区的类型
alter table t3 partition by key(id) partitions 2;
空表修改就已经几百毫秒了,
生产环境是不要贸然进行操作
9.2删除指定RANGE&LIST分区
查看某数据位于哪个分区:
EXPLAIN PARTITIONS SELECT * FROM table_name WHERE my_column = N;
查看某表分区情况及分区数据量:
select table_name,partition_name,table_rows
from information_schema.PARTITIONS
where TABLE_NAME = 'api_log';
删除分区:
alter table t1 drop partition p02;
删除分区数据:
alter table t1 truncate partition p01;
9.3增加RANGE&LIST分区
使用alter table ... add partition语句,
但是对于RANGE分区的表,只能add partition增加新分区到分区列表的高端,不能加到低端
对于LIST分区,不能包含现有分区值列表中的任意值
例:
alter table history_new add partition (partition p202302 values less than (1677600000));
9.4分区重组
使用reorganize可对现有分区重分成多个分区,也可以将多个现有分区合并成一个分区
新分区不能有任何重叠区间(RANGE)或值几何(LIST),还必须覆盖原有区间,
另外合并RANGE分区,只能重新组织相邻分区,不能合并隔着的RANGE分区
alter table t1 reorganize partition p01 into(
partition s0 values less than (5),
partition s1 values less than (10));
alter table t1 reorganize partition s0,s1 into(
partition p01 values less than (10));
一般用于热点分区再拆分
9.5管理HASH&KEY分区数量
使用alter...coalesce partition缩减分区数量
使用alter...add partition增加分区数量
alter table t2 coalesce partition 2;
alter table t2 add partition partitions 6;
注:语句中的数量指的是加减的数量,不是目标数量
9.6分区维护
重建分区:
对于分区表,不支持check table,optimize table, analyze table,repair table(innodb引擎本来也不能用,这些命令都是针对myisam引擎的)
可以使用alter table许多扩展来再一个或多个分区上直接执行这些操作
例如先把数据存在临时文件中,删除分区中记录再重新插入他们,具有同样效果,可用于整理分区碎片(过程有大量IO,不要经常操作)
alter table t1 rebuild partition p01,p02;
优化分区:
如果分区中删除大量的行,或对一个有可变长度的行做了许多修改,可以回收没有使用的空间并整理分区数据文件的碎片(过程相对rebuild性能要稍微好一些,但也还是消耗很高)
alter table t1 optimize partition p01,p02;
检查与修复分区:
用于分区文件损坏等情况,比如意外停机
alter table t1 check partition p01,p02;
alter table t1 repair partition p01,p02;
10.分区索引
mysql分区后每个分区成了独立的文件,虽然从逻辑上还是一张表其实已经分成了多张独立的表,从“information_schema.INNODB_SYS_TABLES”系统表可以看到每个分区都存在独立的TABLE_ID,由于Innodb数据和索引都是保存在".ibd"文件当中(从INNODB_SYS_INDEXES系统表中也可以得到每个索引都是对应各自的分区(primary key和unique也不例外)),所以分区表的索引也是随着各个分区单独存储。
在INNODB_SYS_INDEXES系统表中type代表索引的类型;0:一般的索引,1:(GEN_CLUST_INDEX)不存在主键索引的表,会自动生成一个6个字节的标示值,2:unique索引,3:primary索引;所以当我们在分区表中创建索引时其实也是在每个分区中创建索引,每个分区维护各自的索引(其实也就是local index);对于一般的索引(非主键或者唯一)没什么问题由于索引树中只保留了索引key和主键key(如果存在主键则是主键的key否则就是系统自动生成的6个的key)不受分区的影响;但是如果表中存在主键就不一样了,虽然在每个分区文件中都存在主键索引但是主键索引需要保证全局的唯一性就是所有分区中的主键的值都必须唯一(唯一键也是一样的道理),所以在创建分区时如果表中存在主键或者唯一键那么分区列必须包含主键或者唯一键的部分或者全部列(全部列还好理解,部分列也可以个人猜测是为了各个分区和主键建立关系),由于需要保证全局性又要保证插入数据更新数据到具体的分区所以就需要将分区和主键建立关系,由于通过一般的索引进行查找其它非索引字段需要通过主键如果主键不能保证全局唯一性的话那么就需要去每个分区查找了,这样性能可想而知。
按性能依次降低的顺序,排序如下:
1.主键分区
主键分区即字段是主键同时也是分区字段,性能最好
- 部分主键+分区索引
使用组合主键里面的部分字段作为分区字段,同时将分区字段建索引
3.分区索引
没有主键,只有分区字段且分区字段建索引
4.分区+分区字段没有索引
只建了分区,但是分区字段没有建索引