mysql表分区
• 表分区是将一个表的数据按照一定的规则水平划分为不同的逻辑块,并分别进行物理存储,这个规则就叫做分区函数,可以有不同的分区规则
• 通过show plugins语句查看当前MySQL是否支持表分区功能;5.7表分区功能默认开启;
MySQL表分区介绍
• 当表中含有主键或唯一键时,则每个被用作分区函数的字段必须是表中唯一键和主键的全部或一部分,否则就无法创建分区表
例:
mysql> CREATE TABLE tnp (id INT NOT NULL AUTO_INCREMENT,ref BIGINT NOT NULL,name VARCHAR(255),PRIMARY KEY pk (id),UNIQUE KEY uk (ref) ) PARTITION BY RANGE (id) ( PARTITION p0 VALUES LESS THAN (6), PARTITION p1 VALUES LESS THAN (11));
ERROR 1503 (HY000): A UNIQUE INDEX must include all columns in the table's partitioning function
mysql> CREATE TABLE tnp (id INT NOT NULL AUTO_INCREMENT,ref BIGINT NOT NULL,name VARCHAR(255),PRIMARY KEY pk (id),UNIQUE KEY uk (ref) ) PARTITION BY RANGE (ref) ( PARTITION p0 VALUES LESS THHAN (6), PARTITION p1 VALUES LESS THAN (11));
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function
• 表分区的主要优势在于:
• 可以允许在一个表里存储更多的数据,突破磁盘限制或者文件系统限制
• 对于从表里将过期或历史的数据移除在表分区很容易实现,只要将对应的分区移除即可
• 对某些查询和修改语句来说,可以自动将数据范围缩小到一个或几个表分区上,优化语句执行效率。而且可以通过显示指定表分区来执行语句
例:
SELECT * FROM t PARTITION (p0,p1) WHERE c < 5;
mysql表分区类型
表分区类型分为:
• RANGE表分区:范围表分区,按照一定的范围值来确定每个分区包含的数据
• LIST表分区:列表表分区,按照一个一个确定的值来确定每个分区包含的数据
• HASH表分区:哈希表分区,按照一个自定义的函数返回值来确定每个分区包含的数据
• KEY表分区 :key表分区,与哈希表分区类似,只是用MySQL自己的HASH函数来确定每个分区包含的数据
RANGE表分区
• 范围表分区,按照一定的范围值来确定每个分区包含的数据,分区函数使用的字段必须只能是整数类型
• 分区的定义范围必须是连续的,且不能有重叠部分,通过使用VALUES LESS THAN来定义分区范围,表分区的范围定义是从小到大定义的
例:
CREATE TABLE employees ( id INT NOT NULL, fname VARCHAR(30), lname VARCHAR(30), hired DATE NOT NULL DEFAULT '1970-01-01', separated DATE NOT NULL DEFAULT '9999-12-31', job_code INT NOT NULL, store_id INT NOT NULL )
PARTITION BY RANGE (store_id)
( PARTITION p0 VALUES LESS THAN (6), PARTITION p1 VALUES LESS THAN (11),
PARTITION p2 VALUES LESS THAN (16), PARTITION p3 VALUES LESS THAN (21),PARTITION p4 VALUES LESS THAN MAXVALUE);
• MAXVALUE关键词的作用是表示可能的最大值,所以任何store_id>=21的数据都会被写入到p4分区里
• 对timestamp字段类型可以使用的表达式目前仅有unix_timestamp,其他的表达式都不允许
• 分区函数中也可以使用表达式
LIST表分区
• 列表表分区,按照一个一个确定的值来确定每个分区包含的数据
• 通过PARTITION BY LIST(expr)分区函数表达式必须返回整数,取值范围通过VALUES IN (value_list)定义
例:
mysql> CREATE TABLE h2 (c1 INT, c2 INT )
PARTITION BY LIST(c1)
(PARTITION p0 VALUES IN (1, 4, 7),
PARTITION p1 VALUES IN (2, 5, 8));
• 对List表分区来说,没有MAXVALUE特殊值,所有的可能取值都需要再VALUES IN中包含,如果没有定义的值则会报错
• 同样,当有主键或者唯一键存在的情况下,分区函数字段需要包含在主键或唯一键中
• 对range和list表分区来说,分区函数可以包含多个字段
• 分区多字段函数所涉及的字段类型可以包括:
• TINYINT, SMALLINT, MEDIUMINT, INT (INTEGER), and BIGINT. DATE and DATETIME. CHAR, VARCHAR, BINARY, and VARBINARY; 其他的字段类型都不支持
• 范围多字段分区函数与普通的范围分区函数的区别在于:
a) 字段类型多样化
b) 范围多字段分区函数不支持表达式,只能用字段名
c) 范围多字段分区函数支持一个或多个字段
哈希表分区
• 按照一个自定义的函数返回值来确定每个分区包含的数据,这个自定义函数也可以仅仅是一个字段名字
• 通过PARTITION BY HASH (expr)子句来表达哈希表分区,其中的expr表达式必须返回一个整数,基于分区个数的取模(%)运算。根据余数插入到指定的分区
• 对哈希表分区来说只需要定义分区的个数,其他的事情由内部完成
例:
• CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE) PARTITION BY HASH( YEAR(col3) ) PARTITIONS 4; ##不指定PARTITIONS默认为1
key表分区
与哈希表分区类似,只不过哈希表分区依赖于自定义的函数,而key表分区的哈希算法是依赖MySQL本身
• CREATE TABLE ... PARTITION BY KEY ()创建key表分区,括号里面可以包含0个或者多个字段,所引用的字段必须是主键或者主键的一部分,如果括号里面没有字段,则代表使用主键 ###如果表中没有主键但有惟一键,则使用惟一键,但惟一键必须定义为not null,否则会报错
MySQL表分区对Null值处理
不同的表分区对NULL值的处理方式不同
• 对范围表分区来说,如果插入的是NULL值,则将数据放到最小的分区表里
• 对list表分区来说,支持NULL值的唯一情况就是某个分区的允许值中包含NULL
• 对哈希表分区和Key表分区来说,NULL值会被当成0值对待
MySQL表分区管理
删除表分区
• 通过alter table命令可以执行增加,删除,重新定义,合并或者拆分表分区的管理动作
• 对范围表分区和列表表分区来说,删除一个表分区命令 ###删除表分区的动作不光会把分区删掉,也会把表分区里原来的数据给删除掉
例:
ALTER TABLE tablename DROP PARTITION 分区名称;
增加表分区
• 在原分区上增加一个表分区可以通过alter table … add partition语句来完成
• 但对范围表分区来说,增加的表分区必须在尾部增加,在头部或者在中间增加都会失败;## 为解决这个问题,可以使用REORGANIZE命令:
ALTER TABLE members REORGANIZE PARTITION p0 INTO ( PARTITION n0 VALUES LESS THAN (1970), PARTITION n1 VALUES LESS THAN (1980) );
• 对列表表分区来说,只要新增加的分区对应的值在之前的表分区中没有出现过,就可以通过alter table… add partition来增加
其他管理命令
• 当需要去除分区碎片是,可以执行rebuild命令,相当于删除数据之后重新插入
• ALTER TABLE t1 REBUILD PARTITION p0, p1;
• 也可以执行OPTIMIZE命令回收分区中未使用的空间和重新获取统计资料
• ALTER TABLE t1 OPTIMIZE PARTITION p0, p1;
• Analyzing partitions命令重新收集分区统计资料
• ALTER TABLE t1 ANALYZE PARTITION p3;
• Repairing partitions命令修复异常的分区
• ALTER TABLE t1 REPAIR PARTITION p0,p1;
• Checking partitions命令检查分区中数据或者索引数据是否损坏
• ALTER TABLE t1 CHECK PARTITION p1;
• ALTER TABLE ... TRUNCATE PARTITION命令用来删除分区中的所有数据
实际应用
项目需求:项目中按照时间划分分区使用range分区方式(每周为单位划分一个分区)
1.分区表表结构
表结构定义略...
PARTITION BY RANGE (TO_DAYS(publishtime))
(PARTITION p20190102 VALUES LESS THAN (737427))
2.实现自动增长分区方式
通过mysql事件调度存储过程来实现
具体SQL如下:
创建一个事件
CREATE DEFINER=`d5000`@`%` EVENT `Partition_base_data_event` ON SCHEDULE EVERY 7 DAY STARTS '2019-01-02 10:55:00' ON COMPLETION NOT PRESERVE ENABLE DO CALL create_partition_base_data()
创建存储过程
CREATE DEFINER=`d5000`@`%` PROCEDURE `create_partition_base_data`() BEGIN SET @Max_date= DATE(DATE_ADD(NOW(), INTERVAL 1 DAY))+0; SET @s1=CONCAT('ALTER TABLE base_data ADD PARTITION (PARTITION p',@Max_date,' VALUES LESS THAN (TO_DAYS (''',DATE_ADD(@Max_date, INTERVAL 7 DAY),''')))'); SELECT @s1; PREPARE stmt2 FROM @s1; EXECUTE stmt2; DEALLOCATE PREPARE stmt2; COMMIT ; END