1.分区概述
- 有利于管理非常大的表,他采用了“分而治之”的逻辑。
- 分区引入了分区键的概念,分区键用于根据某个区间值、特定值列表,或者HASH函数生成的数据的聚集。让数据分配在不同的分区中,让一个大对象变成一个小对象
- 分区是对 索引及数据一起分区,不单单只对其中一个分区
查看当前MySQL是否分区
5.6及5.6 之前这样查看
mysql> show plugins like '%partiotion%';
mysql> show variables like '%partition%';
Empty set (0.00 sec) 如果没有则不支持
5.6以后
show plugins;
看见下面就代表支持分区
2.分区类型
分区类型 | 分区键类型 | 分区类型简介 | 使用频率 |
---|---|---|---|
Range分区 | int,或者通过表达式返回int类型 | 基于一个给定的连续区间范围,把数据分配到不同的分区 | 较多 |
List分区 | int,或者通过表达式返回int类型 | 类似Range分区,区别在于List根据枚举出的值列表分区,Range是基于给定的连续区间范围分区 | 一般 |
Hash分区 | int,或者通过表达式返回int类型 | 基于给定的分区个数,将数据分配到不同分区 | 较多 |
Key分区 | 可以使用除int之外其他类型(Blob和text除外) | 类似Hash | 一般 |
- 无论那种分区类型,分区键必须是主键或者唯一键,除非分区表没有主键和唯一键,则可使用其他字段。
- 分区名字根据不同的操作系统就会造成大小写敏感问题。
2.1 Range分区
Range分区的表是根据取值范围将数据分成分区,区间要连续但是不能相互重叠,使用Values Less Than操作符进行定义分区
整数类型
例: 对emp根据store_id就行分区
CREATE TABLE emp (
id INT NOT NULL,
ename VARCHAR ( 30 ),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job VARCHAR(30) NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
PARTITION p0 VALUES LESS THAN (10),
PARTITION pl VALUES LESS THAN (20),
PARTITION p2 VALUES LESS THAN (30)
);
如何我现在添加下列语句,就会报错因为只支持0-9 10-19 20-29
insert into emp(id,ename,hired,job,store_id) values('7934','MILLER','1982-01-23','CLERG',50)
需要我们添加一个,指定大于明确指定的最高值,全部存在这个分区中,类似于编程中的while 循环语句,大于30的全部给p3 现在就能添加成功了
alter table emp add PARTITION(PARTITION p3 VALUES less Than MAXVALUE)
日期类型
正常来说,Range只支持整数类型,但是想要支持日期或者字符串就需要使用函数进行转换为Int,但是5.1只支持两种
- YEAR()
- TO_DAYS()
5.3 之后添加了
c. TO_SECONDS() 精确到了秒
例:
CREATE TABLE emp (
id INT NOT NULL,
ename VARCHAR ( 30 ),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job VARCHAR(30) NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE (Year(separated)) (
PARTITION p0 VALUES LESS THAN (1995),
PARTITION pl VALUES LESS THAN (2000),
PARTITION p2 VALUES LESS THAN (2005)
);
但是在5.5 之后,提供了Range Columns支持非整数类型
例:
CREATE TABLE emp (
id INT NOT NULL,
ename VARCHAR ( 30 ),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job VARCHAR(30) NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE columns (separated) (
PARTITION p0 VALUES LESS THAN ('1995-01-01'),
PARTITION pl VALUES LESS THAN ('2000-01-01'),
PARTITION p2 VALUES LESS THAN ('2005-01-01')
);
Range分区适合以下两点
当删除过期数据的时候,执行一下语句就删了整个分区的内容
Alter table emp Drop PARTITION p0
进行包含分区键进行查询的时候,mysql会找某个或者几个分区,因为其他分区不包含where其中的内容。
2.2 List分区
- 和Range类似,但是他是枚举类型的
- 不存在less Than MAXVALUE 不允许存枚举类型之外的东西
- 1只支持int 5.5 之后List Columns支持非int类型
- 枚举类型不能重复
整数类型
create table expenses(
expense_date Date not null,
category int,
amount decimal (10,3)
)
PARTITION BY LIST(category) (
PARTITION p0 VALUES in (3,5),
PARTITION pl VALUES in (4,2),
PARTITION p2 VALUES in (1,6)
);
如果我使用下列语句 7
insert into expenses(expense_date,category,amount) values('2006-01-23',7,50.2)
varchar类型
是在5.5 之后,提供了List Columns支持非整数类型
create table expenses(
expense_date Date not null,
category VARCHAR(20),
amount decimal (10,3)
)
PARTITION BY LIST columns(category) (
PARTITION p0 VALUES in ('a','v'),
PARTITION pl VALUES in ('r','s'),
PARTITION p2 VALUES in ('f','c')
);
2.3 Columns分区
5.5之后引入了Columns分区,解决了LIST和Range只能使用int作为分区键的问题,Columns细化为以下两种
- RangeColumns
- LIST Columns
支持 整数、日期、字符串三大类型
- 所有整数类型: tinyint、smallint、mediumint、int和bigint;其他数值类型都不支持,例如不支持Decimal和Float。
- 日期时间类型: date和datetime
- 字符类型: char、varchar、binary和varbinary;不支持text和blob类型作为分区键。
支持一个或者多个分区键,可进行多列分区
create Table rc3(
a int,
b int
)
PARTITION BY Range columns(a,b) (
PARTITION p0 VALUES LESS THAN (0,10),
PARTITION p1 VALUES LESS THAN (10,10),
PARTITION p2 VALUES LESS THAN (10,20),
PARTITION p4 VALUES LESS THAN (10,35),
PARTITION p5 VALUES LESS THAN (10,MAXVALUE),
PARTITION p6 VALUES LESS THAN (MAXVALUE,MAXVALUE)
);
INSERT into rc3(a,b) VALUES(va,vb)
如何判断a,b 插入哪个分区呢?? 判断规则是先看左边再看右边 va<a or ((va= a) and vb<b)
- 如果我插入 10,10 符合标准就是p2 10 <10 or (10= 10 and 10<20 )
- 如果我插入1,100 则符合p1 1<10
验证
SELECT (1,100) < (10,10) from DUAL
案例
SELECT
PARTITION_name part,
PARTITION_expression expr,
PARTITION_description descr,
table_rows
FROM
information_schema.PARTITIONS
WHERE
Table_Schema = SCHEMA ()
AND table_name = 'rc3'
查看分区数据量
插入数据
INSERT into rc3(a,b) VALUES(10,10)
查看分区数据
插入数据
INSERT into rc3(a,b) VALUES(1,100)
查看分区数据
2.4 Hash分区
hash分区主要是针对热点读,最好分区键中的值,尽量平均,hash分两种
- 常规HASH,通过取模算法 MOD(expr,num)
- 线性HASH(LINEAR HASH),一个线性的2的幂运算法则
PARTITION BY HASH(expr) PARTITIONs num
expr: 表达式
num: 分区的个数 ,大于0 默认为1
常规HASH
优点: 更好的将数据平均分布到每个分区
缺点: 如果增加或者合并分区的时候,就需要全局计算
CREATE TABLE emp (
id INT NOT NULL,
ename VARCHAR ( 30 ),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job VARCHAR(30) NOT NULL,
store_id INT NOT NULL
)
PARTITION BY HASH(store_id) PARTITIONS 4;
假设现在我将表达式+1 , 则就是 N = Mod(store_id+1,4)
PARTITION BY HASH(store_id+1) PARTITIONS 4;
线性HASH
优点: 能很好处理增加、删除、合并
缺点: 各个分区数据不太均衡
CREATE TABLE emp (
id INT NOT NULL,
ename VARCHAR ( 30 ),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job VARCHAR(30) NOT NULL,
store_id INT NOT NULL
)
PARTITION BY LINEAR HASH(store_id) PARTITIONS 4;
2.5 Key分区
key分区与Hash分区非常类似,也是常规和线性算法也是一样的
- 只不过Hash允许自定义分区,而key不支持自定义分区,需要使用服务器自带的Hash函数
- Hash分区只支持整数,而Key除了blob 和 Text,其他都能支持
- 在按照Key分区时,不能使用 Alter table drop PRIMARY KEY删除主键,不然会报错
PARTITION BY key(expr) PARTITIONs num
expr: 可以是0个或者多个字段名的列表,如果为0 则指定 主键、非空唯一键,依次为区分键,如果既没有主键,也没唯一键则不能不指定区分键
num: 分区个数
2.6 子分区
对分区表进行再次分割,又称复合分区,从5.1开始可以对Range或者List分区了的表在进行分区,子分区可以使用HASH或者Key
CREATE TABLE emp (
id INT NOT NULL,
ename VARCHAR ( 30 ),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job VARCHAR(30) NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) Subpartition by HASH(store_id) Subpartitions 2 (
PARTITION p0 VALUES LESS THAN (10),
PARTITION pl VALUES LESS THAN (20),
PARTITION p2 VALUES LESS THAN (30)
);
对emp进行了p0,p1,p2 分区,每个分区又分了2个HASH分区,则这个表一共有6个分区。使用保存非常大的表
2.7 Mysql分区处理NULL值得方式
mysql 不禁止在分区键值上的null,分区键可能是一个字段或者自定义的表达式。
- Range分区中,null会被当做最小值处理
- List分区中, 如果null在枚举中,则允许插入。 如果枚举没定义,则会抛错
- hash和key中,null会被当做零值处理
为了避免null的影响,建议设置非空和设置默认值来避免null的影响
3. 分区管理
主要就是分区的 增加,删除,添加, 查询
3.1 Range和List
删除
删除分区,同时也会将分区中数据全部删除,但是List因为删除分区会删除枚举类型,则被删除的枚举类型就不能再添加了。
Alter Table Drop Partiton partiton_name;
增加
Range分区只能从分区的最大端添加,List不能添加已有的枚举类型
Alter Table table_name Add Partiton (
PARTITION p0 VALUES LESS THAN (10),
);
Alter Table table_name Add Partiton (
PARTITION p0 VALUES in (3,5),
);
重新定义分区
mysql提供了在不丢失数据情况下,重新定义分区
对Range进行重新定义,必须要与原分区覆盖相同的区间,分区合并的时候,必须是相邻的分区,不能跳过。也不能变化分区类型,不能将Range分区变成Hash分区
拆分一个为多个 将p3拆分为 p2 p3
Alter Table table_name reorganize Partiton p3 into( PARTITION p2 VALUES LESS THAN (10), PARTITION p3 VALUES LESS THAN (30), );
合并多个为一个 将 p2 p3 合并成一个
Alter Table table_name reorganize Partiton p2,p3 into( PARTITION p3 VALUES LESS THAN (30), );
对LIst 操作,下面例子给p4增加枚举11 首先新增一个分区p6,在进行重新分配,这个重新分配也必须是在相邻区间,必须要与原分区覆盖相同的区间。也不能变化分区类型,不能将Range分区变成Hash分区
- 增加p4(6)区间的枚举类型 11 不能直接添加分两步 首先新增一个分区,在合并
```sql
Alter Table table_name Add Partiton (
PARTITION p6 VALUES in (11), );
alter table table_name reorganize partition p4,p5,p6 into( partition p4 values in (6,11), partition p5 values in (7,8) )
<a name="L91zc"></a>
## 3.2 Hash和key
这个只是对分区的数量进行改变,新增是新增多少个,不是新增到多少个
<a name="IgIc6"></a>
### 减少
减少两个,不能超过已有的分区,本来只有4个你不能删除4个及以上
```sql
alter table table_name coalesce partition 2;
增加
新增八个
alter table table_name add partition partitions 8;