1、分区概念
mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下面(可以通过my.cnf中的datadir来查看),一张表主要对应着三个文件(8.0对应两个,往期版本三个)一个是frm存放表结构的,一个是myd存放表数据的,一个是myi存表索引的(innodb同理)。
如果一张表的数据量太大的话,那么myd,myi就会变的很大,查找数据就会变的很慢,这个时候我们可以利用mysql的分区功能,在物理上将这一张表对应的三个文件,分割成许多个小块,这样呢,我们查找一条数据时,就不用全部查找了,只要知道这条数据在哪一块,然后在那一块找就行了。如果表的数据太大,可能一个磁盘放不下,这个时候,我们可以把数据分配到不同的磁盘里面去。
表分区,是指根据一定规则,将数据库中的一张表分解成多个更小的,容易管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成。
2、分区优点
- 与单个磁盘或文件系统分区相比,可以存储更多的数据。
- 对于那些已经失去保存意义的数据,通常可以通过删除与那些数据有关的分区,很容易地删除那些数据。相反地,在某些情况下,添加新数据的过程又可以通过为那些新数据专门增加一个新的分区,来很方便地实现。
- 一些查询可以得到极大的优化,这主要是借助于满足一个给定WHERE语句的数据可以只保存在一个或多个分区内,这样在查找时就不用查找其他剩余的分区。因为分区可以在创建了分区表后进行修改,所以在第一次配置分区方案时还不曾这么做时,可以重新组织数据,来提高那些常用查询的效率。
- 涉及到例如SUM()和COUNT()这样聚合函数的查询,可以很容易地进行并行处理。这种查询的一个简单例子如 “SELECT salesperson_id, COUNT (orders) as order_total FROM sales GROUP BY salesperson_id;”。通过“并行”,这意味着该查询可以在每个分区上同时进行,最终结果只需通过总计所有分区得到的结果。
- 通过跨多个磁盘来分散数据查询,来获得更大的查询吞吐量。
3、分区限制
- 一个表最多只能有1024个分区。
- MySQL5.1中,分区表达式必须是整数,或者返回整数的表达式。在MySQL5.5中提供了非整数表达式分区的支持。
- 如果分区字段中有主键或者唯一索引的列,那么所有主键列和唯一索引列都必须包含进来。即:分区字段要么不包含主键或者索引列,要么包含全部主键和索引列。
- 分区表中无法使用外键约束。
- MySQL的分区适用于一个表的所有数据和索引,不能只对表数据分区而不对索引分区,也不能只对索引分区而不对表分区,也不能只对表的一部分数据分区。
4、分区类型
- RANGE分区:基于属于一个给定连续区间的列值,把多行分配给分区。
range分区使用values less than 操作符来进行定义, 把连续且不相互重叠的字段分配给分区,命令如下。
create table emp(
`no` varchar(20) not null,
`name` varchar(20),
deptno int,
birthdate date,
salary int
)
partition by range(salary) (
partition p1 values less than(1000),
partition p2 values less than(5000),
partition p3 values less than(10000)
);
insert into emp values('001', 'shineyork', 10, '2019-10-10', 5000);
insert into emp values('002', 'keke', 20, '2019-10-10', 1500);
insert into emp values('004', 'n', 20, '2019-10-10', 1000);
insert into emp values('004', 'c', 20, '2019-10-10', 6000);
如上的方式就是把数据根据salary的value进行划分,区分到不同的表分区中;而这其中partition by range的语法类似于“switch..case”的语法,如果salary小余5000就会在p1中...当salary大于10000会报错
mysql> insert into emp values('003', 'a', 10, '2019-10-10', 10500);
ERROR 1526 (HY000): Table has no partition for value 10500
这是因为10000不在分区范围内,解决这个问题的办法就是在其后加入“partition p4 values less than maxvalue” 语法,这样所有大于10000的数据都会存在p4分区中
partition by range(salary) (
partition p1 values less than(1000),
partition p2 values less than(5000),
partition p3 values less than(10000),
partition p4 values less than maxvalue
)
查询分区之后某一个区中的数据
select * from emp partition (p3);
在range中也可以使用MySQL的系统函数,比如根据年龄进行区分
create table emp(
`no` varchar(20) not null,
`name` varchar(20),
deptno int,
birthdate date,
salary int
)
partition by range(year(birthdate)) (
partition p1 values less than(1990),
partition p2 values less than(2000),
partition p3 values less than(2010),
partition p4 values less than maxvalue
)
- LIST分区:类似于range分区,区别在于list中的每个分区的定义和选择基于某列的值从属于一个集合,而range分区是属于一个连续区间值得集合。
create table emp(
`no` varchar(20) not null,
`name` varchar(20),
deptno int,
birthdate date,
salary int
)
partition by list(deptno) (
partition p1 values in (10,20,30),
partition p2 values in (1,2,3),
partition p4 values in (4,40)
);
insert into emp values('001', 'shineyork', 1, '2019-10-10', 5000);
insert into emp values('002', 'keke', 20, '2019-10-10', 1500);
insert into emp values('003', 'a', 10, '2019-10-10', 10500);
insert into emp values('004', 'n', 40, '2019-10-10', 1000);
insert into emp values('005', 'c', 6, '2019-10-10', 6000);
mysql> insert into emp values('005', 'c', 6, '2019-10-10', 6000);
ERROR 1526 (HY000): Table has no partition for value 6
- HASH分区:HASH分区是基于用户定义的表达式的返回值来进行选择的分区,该表达式使用将要插入到表中的这些行的列值进行计算。这个函数可以包含MySQL中有效的、产生非负整数值的任何表达式。
HASH分区主要用来确保数据在预先确定数目的分区中平均分布。 在RANGE和LIST分区中,必须明确指定一个给定的列值或列值集合应该保存在哪个分区中;而在HASH分区中,MySOL自动完成这些工作,用户所要做的只是基于将要被哈希的列值指定一个列值或表达式,以及指定被分区的表将要被分割成的分区数量。
create table emp(
`no` varchar(20) not null,
`name` varchar(20),
deptno int,
birthdate date,
salary int
)
partition by hash(year(birthdate)) partitions 4;
- KEY分区:类似于hash分区,区别在于key分区只支持计算一列或多列,且MySQL服务器其自身的哈希函数,必须有一列或多列包含整数值。这些函数是基于password()一样的运算规则
create table emp(
`no` varchar(20) not null,
`name` varchar(20),
deptno int,
birthdate date,
salary int
)
partition by key(year(birthdate)) partitions 4;
*说明:在MySQL5.1版本中,RANGE,LIST,HASH分区要求分区键必须是INT类型,或者通过表达式返回INT类型。但KEY分区的时候,可以使用其他类型的列(BLOB,TEXT类型除外)作为分区键。