分区表是什么呢?我们举个场景:数据量非常非常大的时候,一张表存储了上亿条数据,而且只有一部分数据或者是最近的数据经常使用(热点数据)。
这个时候,同一张表的数据在物理层面都是存放在一起的,管理上十分不方便。
分区则可以将一张表从物理层面根据一定的规则将数据划分为多个分区,多个分区可以单独管理,甚至存放在不同的磁盘/文件系统上,提升效率。
简单来说,分而治之。
而且其和分库分表不同,前者是垂直分区(表到不同服务器),后者是水平分区(按数据量划分物理机器)。
分区表是一个独立的逻辑表,但是底层由多个物理子表组成。分区实现实际上是对一组底层表的句柄对象的封装,由句柄对象标识后我们可以直接访问各个分区。对分区表的请求,都会通过句柄对象转化成对存储引擎的接口调用。
存储引擎管理分区的各个底层表和管理普通表一样(所有的底层表都必须使用相同的存储引擎),分区表的索引只是在各个底层表上各自加上一个完全相同的索引。从存储引擎的角度来看,底层表和普通表没有任何不同,存储引擎也无须知道这是一个普通表还是一个分区表的一部分。
在创建表时使用PARTITION BY子句定义每个分区存放的数据。
根据某一列的落在给定范围内的值将数据行分配给分区。
CREATE TABLE testFQ(
id INT NOT NULL,
name VARCHAR(30),
create_date DATE NOT NULL DEFAULT '1970-01-01',
update_date DATE NOT NULL DEFAULT '9999-12-31'
)
PARTITION BY RANGE (id) (
PARTITION p0 VALUES LESS THAN (51),
PARTITION p1 VALUES LESS THAN (101),
PARTITION p2 VALUES LESS THAN (151),
PARTITION p3 VALUES LESS THAN MAXVALUE );
--
--maxvalue表示最大可能整数值的整数值
或者,根据时间分区:
CREATE TABLE testFQ(
id INT NOT NULL,
name VARCHAR(30),
create_date DATE NOT NULL DEFAULT '1970-01-01',
update_date DATE NOT NULL DEFAULT '9999-12-31'
)
PARTITION BY RANGE (create_date ) (
PARTITION p0 VALUES LESS THAN (1980-01-01),
PARTITION p1 VALUES LESS THAN (1990-01-01),
PARTITION p2 VALUES LESS THAN (2000-01-01),
PARTITION p3 VALUES LESS THAN MAXVALUE );
查询分区:
select * from testFQ partition(p0); -- 查询p0分区
select * from testFQ partition(p0,p1); -- 查询p0和p1分区
与范围分区类似,主要区别是list partition的分区范围是预先定义好的一系列值,而不是连续的范围。
CREATE TABLE testFQ(
id INT NOT NULL,
name VARCHAR(30),
create_date DATE NOT NULL DEFAULT '1970-01-01',
update_date DATE NOT NULL DEFAULT '9999-12-31',
user_id INT NOT NULL
)
PARTITION BY LIST(user_id) (
PARTITION pNorth VALUES IN (3,5,6,9,17),
PARTITION pEast VALUES IN (1,2,10,11,19,20),
PARTITION pWest VALUES IN (4,12,13,14,18),
PARTITION pCentral VALUES IN (7,8,15,16)
);
基于用户定义的表达式的返回值(最终通过hash函数)来进行选择的分区,该表达式使用指定的列值进行计算。这个函数可以包含myql中有效的、产生非负整数值的任何表达式。
主要的应用场景是将数据平均的分布在指定数量的hash分区中。在range和list分区类型中,根据分区条件的计算结果,数据可以确定存储在哪个分区,而在hash分区中,数据存储在某个分区是由数据库自己决定的,你只需要指定分区的数量。
CREATE TABLE testFQ(
id INT NOT NULL,
name VARCHAR(30),
create_date DATE NOT NULL DEFAULT '1970-01-01',
update_date DATE NOT NULL DEFAULT '9999-12-31',
user_id INT NOT NULL
)
PARTITION BY HASH(user_id)
PARTITIONS 4; --分成4个分区
或者
CREATE TABLE testFQ(
id INT NOT NULL,
name VARCHAR(30),
create_date DATE NOT NULL DEFAULT '1970-01-01',
update_date DATE NOT NULL DEFAULT '9999-12-31',
user_id INT NOT NULL
)
PARTITION BY LINEAR HASH(YEAR(create_date))--自定义函数
PARTITIONS 4; --分成4个分区
与hash分区类似,主要区别在于key分区的hash函数是由MySQL server提供的,且使用主键(或非空唯一键)作为分区列。
CREATE TABLE testFQ(
id INT NOT NULL PRIMARY KEY,
name VARCHAR(30),
create_date DATE NOT NULL DEFAULT '1970-01-01',
update_date DATE NOT NULL DEFAULT '9999-12-31',
user_id INT NOT NULL
)
PARTITION BY KEY() -- 未指定分区列,自动使用主键
PARTITIONS 4; --分成4个分区
在分区上再分区。
CREATE TABLE testFQ(
id INT NOT NULL PRIMARY KEY,
name VARCHAR(30),
create_date DATE NOT NULL DEFAULT '1970-01-01',
update_date DATE NOT NULL DEFAULT '9999-12-31',
user_id INT NOT NULL
)
PARTITION BY RANGE( YEAR(create_date ) ) -- 父分区采用range partition
SUBPARTITION BY HASH( TO_DAYS(create_date ) ) -- 子分区采用hash partition
SUBPARTITIONS 2 -- 子分区数量为2
(
PARTITION p0 VALUES LESS THAN (1990),
PARTITION p1 VALUES LESS THAN (2000),
PARTITION p2 VALUES LESS THAN MAXVALUE
);
select * from testFQ partition(p0); -- 查询p0分区
select * from testFQ partition(p0,p1); -- 查询p0和p1分区
alter table testFQ drop partition p1;
分区新增只能在最大范围之上增加分区。
alter table testFQ add partition (partition n1 values less than(1000));
要在分区之间插入新的分区,则可以采用重组织的方式,将已有分区的数据重新划分:
在101-151中间再插一个分区:
alter table testFQ reorganize partition p2 into (
partition p1 values less than(101),
partition p2 values less than(121))
清除分区中所有记录,然后在重新插入。
ALTER TABLE testFQ REBUILD PARTITION p0, p1; -- 重建p0,p1分区
ALTER TABLE testFQ REBUILD PARTITION ALL; -- 重建所有分区
用check table语句来检查指定分区是否存在损坏:
ALTER TABLE testFQ CHECK PARTITION p1; -- 检查p1分区
ALTER TABLE testFQ CHECK PARTITION all; -- 检查所有分区
统计指定分区的键值分布,可以更好的生成执行计划:
ALTER TABLE testFQ ANALYZE PARTITION p1; -- 分析p1分区
ALTER TABLE testFQ ANALYZE PARTITION all; -- 分析所有分区
修复损坏的分区:
ALTER TABLE testFQ REPAIRP ARTITION p1; -- 修复p1分区
ALTER TABLE testFQ REPAIR PARTITION all; -- 修复所有分区
分区存在大量的数据更新,你可以使用optimize partition来回收空间,收集统计信息。其效果相当于在分区上执执行check partition、analyze partition 和 repair partition一样。
ALTER TABLE testFQ OPTIMIZE PARTITION p0;
1、使用简单的分区方式存放表,不要任何索引,根据分区规则大致定位需要的数据为止,通过使用where条件将需要的数据限制在少数分区中,这种策略适用于以正常的方式访问大量数据。
2、 如果数据有明显的热点,而且除了这部分数据,其他数据很少被访问到,那么可以将这部分热点数据单独放在一个分区中,让这个分区的数据能够有机会都缓存在内存中,这样查询就可以只访问一个很小的分区表,能够使用索引,也能够有效的使用缓存。