MYSQL分区
分区的优点
- 存储更多数据
- 优化查询,只扫描必要的一个或者多个分区,针对count()和sum()只要对分区统计再汇总
- 对于过期或不需要保存的数据,操作分区更快
- 跨多个磁盘来分散数据查询,以获得更大的查询吞吐量
分区概述
分区键的引入。
查询是否支持分区
mysql> show variables like '%partition%';Empty set (0.01 sec)mysql> show variables like '%partition%';+---------------------------------------+-------+| Variable_name | Value |+---------------------------------------+-------+| innodb_adaptive_hash_index_partitions | 1 |+---------------------------------------+-------+
MySQL支持创建分区的引擎:MyISam、InnoDB、Memory,不支持分区:MERGE、CSV
在MySQL5.1中,同一个分区表的所有分区必须使用同一个存储引擎,但是在同一个MySQL服务器中或者同一个数据库中、对于不同的分区表可以使用不同的存储引擎。
MySQL的分区适用于一个表的所有数据和索引。
设置引擎ENGINE必须在CREATE TABLE语句中的其他任何部分之前
mysql> create table emp(empid int,salay decimal(7,2),birth_date date) engine=innodb partition by hash(month(birth_date)) partitions 6;Query OK, 0 rows affected (0.06 sec)
分区类型
- RANGE 分区:基于属于一个给定连续区间的列值,把多行分配给分区。
- LIST 分区:类似于RANGE分区,区别在于LIST分区是基于枚举出的值列表分区,RANGE是基于给定的连续区间范围分区
- HASH分区:基于给定的分区个数,把数据分配到不同的分区
- KEY分区:类似于RANGE分区
在mysql5.1中:range、list、hash分区键必须是int类型,key还可以使用blog、text。在mysql5.5中已经支持非整数类型做分区键
分区时注意
- 要么分区表上没有主键/唯一键,要么分区表主键/唯一键必须包含分区键。(否则会报错)
- 分区的名字不区分大小写
RANGE分区
利用取值范围将数据分成分区,区间要连续且不能互相重叠。
RANGE分区中,分区键如果是NULL值会被当作一个最小值来处理。
mysql> create table emp_date( 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 p1 values less than (2000), partition p2 values less than (2005) );Query OK, 0 rows affected (0.04 sec)
超出最大分区范围会报错,要是有个最大值maxvalue
兜底就好了!你想要的都给你!
mysql> alter table emp_date add partition (partition p3 values less than maxvalue);Query OK, 0 rows affected (0.04 sec)Records: 0 Duplicates: 0 Warnings: 0
前面说了RANGE只支持int做分区键,太没有人性了,现实业务场景那么多,MySQL5.5起改进了这个问题,新增RANGE COLUMNS 分区支持非整型分区,这样创建日期分区就不用通过函数多此一举了。no code no bb!
mysql> drop table `emp_date`;Query OK, 0 rows affected (0.04 sec)mysql> create table emp_date( -> 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 p1 values less than ('2000-01-01'), -> partition p2 values less than ('2005-01-01') -> );Query OK, 0 rows affected (0.04 sec)
这种操作还不够常用,经常要按天分区怎么搞?
MySQL5.1:分区日期处理函数只有year()
和to_days()
MySQL5.5:增加了to_seconds()
,把日期转换成秒。
说了那么多,RANGE分区功能特别适用哪些情况?
- 当需要删除过期的数据,比如某个分区的数据已经完全没有意义了,请执行
alter table emp_date drop partition p0
删除分区。对动辄成千上万的数据,比运行delete要高效的多! - 经常运行包含分区键的查询,MySQL很快能找到对应的分区,并且在对应的分区扫描。
mysql> insert into emp_date (id,ename,hired,separated,job,store_id) values('7934','miller','1995-01-01','1995-01-01','care',50);Query OK, 1 row affected (0.01 sec)mysql> explain partitions select count(1) from emp_date where store_id >=20\G;*************************** 1. row *************************** id: 1 select_type: SIMPLE table: emp_date partitions: p0,p1,p2 type: ALLpossible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1 filtered: 100.00 Extra: Using where1 row in set, 2 warnings (0.00 sec)ERROR: No query specified
LIST分区
特点:一个枚举列表的值的集合。RANGE是连续区间值的集合
mysql> 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 p1 VALUES IN ( 1, 11 ), -> PARTITION p2 VALUES IN ( 4, 9 ), -> PARTITION p3 VALUES IN ( 2 ) -> );Query OK, 0 rows affected (0.07 sec)
前面有说过,LIST也是仅支持整型,如果你是MySQL5.1,还得单独建个表。
MYSQL5.5中支持非整型分区,真贴心!
mysql> CREATE TABLE expensess ( -> expense_date date NOT NULL, -> category varchar (30), -> amount DECIMAL ( 10, 3 ) -> ) -> PARTITION BY list columns ( category ) ( -> PARTITION p0 VALUES IN ('loading','food' ), -> PARTITION p1 VALUES IN ( 'ear', 'frist' ), -> PARTITION p2 VALUES IN ( 'hire','horse' ), -> PARTITION p3 VALUES IN ( 'fees' ) -> );Query OK, 0 rows affected (0.06 sec)
LIST分区,整型是list (expr) ,字符串是list columns (expr)