分区简介mysql
分区是根据必定的规则,数据库把一个表分解成多个更小的、更容易管理的部分。就访问数据库应用而言,逻辑上就只有一个表或者一个索引,但实际上这个表可能有N个物理分区对象组成,每一个分区都是一个独立的对象,能够独立处理,能够做为表的一部分进行处理。分区对应用来讲是彻底透明的,不影响应用的业务逻辑。算法
分区有利于管理很是大的表,它采用分而治之的逻辑,分区引入了分区键的概念,分区键用于根据某个区间值(或者范围值)、特定值列表或者 hash函数值执行数据的汇集,让数据根据规则分布在不一样的分区中,让一个大对象变成多个小对象。
sql
Mysql分区既能够对数据进行分区也能够对索引进行分区。数据库
MySQL分区表对分区字段的限制服务器
分区的字段,必须是表上全部的惟一索引(或者主键索引)包含的字段的子集。less
换句话说:(全部的)字段必须出如今(全部的)惟一索引或者主键索引的字段中,或者说:一个表上有一个或者多个惟一索引的状况下,分区的字段必须被包含在全部的主键或者惟一索引字段中。函数
分区类型大数据
range分区:基于一个给定的连续区间范围(区间要求连续而且不能重叠),把数据分配到不一样的分区优化
list分区:相似于range分区,区别在于list分区是基于枚举出的值列表分区,range是基于给定的连续区间范围分区spa
hash分区:基于给定的分区个数,把数据分配到不一样的分区
key分区:相似于hash分区
MySQL分区的优势主要包括如下4个方面
1)和单个磁盘或者文件系统分区相比,能够存储更多数据
2)优化查询。在where子句中含有分区条件时,能够只扫描必要的一个或者多个分区来提升查询效率;同时,在设计sum()和count() 这类聚合函数查询时,能够容易的在每一个分区上并行处理,最终只须要汇总全部分区获得的结果
3)对于已通过期或者不须要保存的数据,能够经过删除与这些数据有关的分区来快速删除数据
4)跨多个磁盘来分散数据查询,以得到更大的查询吞吐量
分区和水平分表功能相似,将一个大表的数据分割到多张小表中去,因为查询不须要全表扫描了,只要扫描某些分区,因此分区能提升查询速度。
水平分表须要用户预先手动显式建立出多张分表(如 tbl_user0,tbl_user1,tbl_user2),在物理上实实在在的建立多张表,经过客户端代理(Sharding-JDBC等)或者中间件代理(mycat等)来实现分表逻辑。
分区是Mysql的一个插件Plugin功能,将一张大表的数据在数据库底层分红多个分区文件(如 tbl_user#P#p0.ibd,tbl_user#P#p1.ibd,tbl_user#P#p2.ibd),和水平分表不一样的是分区不须要显示的建立“分表”,数据库会自动建立分区文件,用户看到的只是一张普通的表,实际上是对应的多个分区,这个是对用户是屏蔽、透明的,在使用上和使用一张表彻底同样,不须要借助任何功能来实现。分区是一种逻辑上的水平分表,在物理层面仍是一张表。
数据库文件
create table tbl_user_innodb(
id int(11) not null auto_increment,
username varchar(255),
email varchar(20),
age tinyint(4),
type int(11),
create_time datetime default current_timestamp,
primary key (id)
) engine=InnoDB auto_increment=5100002;
create table tbl_user_myisam(
id int(11) not null auto_increment,
username varchar(255),
email varchar(20),
age tinyint(4),
type int(11),
create_time datetime default current_timestamp,
primary key (id)
) engine=myisam auto_increment=5100002;
经过show variables like '%datadir%'; 命令查看mysql的data存放目录,进入所在的数据库目录,不一样的引擎数据库文件格式不一样
myisan: .frm 存储表结构 + .MYD 存储表数据 + .MYI 存储索引文件
innodb: .frm 存储表结构 + .ibd 存储数据和索引 (其只有设置成独立表空间才能成功表分区)
插入500w条数据
range分区
Mysql有五种分区类型,range、list、hash、key、子分区,其中最经常使用的是range 和 list 分区
-- 查看mysql版本
select version();
-- 查看分区插件是否激活 partition active
show plugins;
对于低版本的 mysql,若是InnoDB引擎要想分区成功,须要在 my.conf 中设置 innodb_file_per_table=1 设置独立表空间(即,每张表都有对应的.ibd文件)
range 分区:给定一个连续区间的范围值进行分区,某个字段的值知足这个范围就会被分配到该区。适用于字段的值是连续的区间的字段,如,日期范围,连续的数字
-- 语法
create table <tablename> (
// 字段
)ENGIN=MyISAM DEFAULT CHARSET=UTF-8 AUTO_INCREMENT=1
partition by range (分区字段) (
partition <分区名称> values less than (value),
partition <分区名称> values less than (value),
...
partition <分区名称> values less than maxvalue
);
range 表示按范围分区
分区字段:表示要按照哪一个字段进行分区,能够是一个字段名,也能够是对某个字段进行表达式运算,如 year(create_time),使用 range 最终的值必须是数字
分区名称:要保证不一样,也能够采用 p0,p1,p2 这样的分区名称
value:表示要小于某个具体的值,如 less than (10),那么分区字段的值小于10的都会被分到这个分区
maxvalue:表示一个最大值
注意:range 对应的分区键值必须是数字值,可使用 range columns(分区字段) 对非 int 型作分区,如字符串,对于日期类型的可使用year()、to_days()、to_seconds() 等函数
create table emp_date(
id int not null,
separated date not null default '9999-12-31'
) partition by range columns(separated) (
partition p0 values less than ('1990-01-01'),
partition p1 values less than ('2001-01-01'),
parttion p2 values less than ('2018-01-01')
)
分区可在建立表的时候进行分区,也能够在建立表以后进行分区
alter table <table> partition by range(id) (
partition p0 values less than (100000),
partition p1 values less than (200000),
partition p2 values less than (300000)
);
在建立分区的时候,常常会遇到这个错误:A PRIMARY KEY must include all columns in the table's partition function。意思是分区的字段必需要包含在主键当中。可使用 PRIMARY KEY(id, xxx) 来将多个字段做为主键。在作分区表时,选择分区的依据字段时要谨慎,须要仔细斟酌这个字段拿来做为分区依据是否合适,这个字段加入到主键中做为复合主键是否适合。
使用 range 分区时,表结构要么没有主键,要么分区字段必须是主键。
list分区
设置若干个固定值进行分区,若是某个字段的值在这个设置的值列表中就会被分配到该分区。适用于字段的值区分度不高的,或者值有限的,特别像枚举这样特色的列。list 分区使用 in 表示一些固定的值的列表
-- 语法
create table <table> (
//字段
) partition by list (分区字段或者基于该字段的返回的整数值的表达式) (
partition <分区名称> values IN (value1, value2,value3),
...
partition <分区名称> values IN (value4, value5)
)
columns分区
在mysql5.5以前 range分区和list分区只支持整数分区,能够经过额外的函数运算或额外的转换从而获得一个整数。columns 分区分为 range columns 和 list columns 两种,支持整数(tinyint 到 bigint,不支持 decimal 和 float)、日期(date、datetime)、字符串(char、varchar、binary、varbinary)三大数据类型。
columns 分区支持一个或者多个字段做为分区键,不支持表达式做为分区键,这点区别于 range 和 list 分区。须要注意的是 range columns 分区键的比较是基于元组的比较,也就是基于字段组的比较,这和 range 分区有差别。
create table rc3(
a int,
b int
) partition by range columns(a, b) (
partition p01 values less than (0, 10),
partition p02 values less than (10, 10),
partition p03 values less than (10, 20),
partition p04 values less than (10, 35),
partition p05 values less than (10, maxvalue),
partition p06 values less than (maxvalue, maxvalue)
)
range columns 分区键的比较(元组的比较)其实就是多列排序,先根据 a 字段排序,再根据 b 字段排序,根据排序结果来分区存放数据,和 range 单字段的分区排序规则其实是同样的。
hash分区
hash分区主要用来分散热点读,确保数据在预先肯定个数的分区中可能的平均分布。对一个表执行 hash 分区时,mysql 会对分区键应用一个散列函数,以此肯定数据应当放在N个分区中的哪一个分区。
mysql支持两种 hash 分区,常规hash分区和线性hash分区(linear hash分区)
常规hash分区使用的是取模算法,对应一个表达式 expr 是能够计算出它被保存在哪一个分区中,N=MOD(expr, num)
线性 hash 分区使用的是一个线性的2的幂运算法则。
对指定的字段(整数字段)进行哈希,将记录平均的分配到分区中,使得全部的分区的数据比较平均。hash 分区只须要指定分区的字段和要分红几个分区
expr是一个字段值或者基于某列值运算返回的一个整数,expr能够是 mysql 中有效的任何函数或者其余表达式,只要他们返回一个即很是熟也非随机数的整数。
num 表示分区的数量(看得出来,他是模运算的基数)
create table <table> (
// 字段
) engine=数据库引擎 default charset=utf8 auto_increment=1
partition by hash(expr)
partitions <num>
常规 hash 分区方式看上去不错,经过取模的方式来让数据尽量平均分布在每一个分区,让每一个分区管理的数据都减小,提升查询效率,但是当咱们要增长分区或者合并分区,问题就来了,假设原来是5个分区,如今须要增长一个分区,原来的取模算法是MOD(expr, 5),根据余数 0-4 分布在5个分区中,如今新增一个分区后,取模算法变成 MOD(expr, 6),根据余数 0-5 分区在6个分区中,原来5个分区的数据大部分都须要从新计算进行从新分区。
常规 hash 分区在管理上带来的代价太大,不适合须要灵活变更分区的需求。为了下降分区管理上的代价,mysql提供了线性 hash 分区,分区函数是一个线性的 2 的幂的运算法则。一样线性 hash 分区的记录被存在哪一个分区也能被计算出来。线性hash分区的优势是在分区维护(增长、删除、合并、拆分分区)时,mysql可以处理的更加迅速,缺点是:对比常规hash分区,线性hash 各个分区之间数据的分布不太均衡。
create table <tablename> (
// 字段
) engine=数据引擎 default charset = utf-8 auto_increment=1
partition by linear hash(expr)
partitions <num>;
key分区
按照key进行分区很是相似于按照 hash 进行分区,只不过 hash 分区容许使用用户自定义的表达式,而key分区不容许使用自定义的表达式,须要使用 mysql 服务器提供的 hash 函数,同事 hash 分区只支持整数分区,而 key 分区支持使除了 blob or text 类型外的其余类型做为分区键。
和 hash 功能同样,不一样的是分区的字段能够是非 int 类型,如字符串、日期类型。
可使用 partition by key(expr) 子句来建立一个 key 分区表,expr 是零个或者多个字段名的列表。key 分区也支持线性分区 linear key
partition by key(expr) partitions num;
-- 不指定默认首选主键做为分区键,在没有主键的状况下会选择非空惟一键做为分区键
partition by key() partitions num;
-- linear key
partition by linear key(expr);
子分区
子分区是分区表中对每一个分区的再次分割,又被称为复合分区,支持对 range 和 list 进行子分区,子分区既可使用 hash分区,也可使用 key分区。符合分区适用于保存很是大量数据记录。
管理分区
mysql 不由止在分区键值上使用 null,分区键多是一个字段或者一个用户的定义的表达式,通常状况下,mysql 的分区把 null 值当作零值或者一个最小值进行处理。range 分区中,null 值会被当作最小值来处理;list分区中 null 值必须出如今枚举列表中,不然不被接受;hash/key 分区中,null 值会被当作 0 值来处理。
mysql 提供了添加、删除、重定义、合并、拆分分区的命令,这些操做均可以经过 alter table 命令来实现
-- 删除 list 或者 range 分区(同时删除分区对应的数据)
alter table <table> drop partition <分区名称>;
-- 新增分区
-- range 添加新分区
alter table <table> add partition(partition p4 values less than MAXVALUE);
-- list 添加新分区
alter table <table> add partition(partition p4 values in (25,26,28));
-- hash 从新分区
alter table <table> add partition partitions 4;
-- key 从新分区
alter table <table> add partition partition 4;
-- 子分区添加新分区,虽然没有指定子分区,可是系统会给子分区命名
alter table <table> add partition(partition p3 values less than MAXVALUE)
-- range 从新分区
alter table user reorganize partition p0,p1,p2,p3,p4 into (partition p0 values less than maxvalue);
-- list 从新分区
alter table <table> reorganize partition p0,p1,p2,p3,p4 into (partition p0 values in (1,2,3,4,5))
分区优势
1. 分区能够分在多个磁盘,存储更大一些
2. 根据查找条件,只查找相应的分区,不用所有查找
3. 进行大数据搜索时,能够并行处理
4. 跨多个磁盘来分散数据查询,来得到更大的查询吞吐量
https://blog.csdn.net/vbirdbest/article/details/82461109