将一个表或者索引分解为多个更小、更可管理的部分mysql
目前只支持水平分区sql
只支持局部分区索引数据库
每一个分区保存本身的数据与索引函数
分区列必须是惟一索引的一个组成部分性能
CREATE TABLE T1( col1 INT NOT NULL, col2 DATE NOT NULL, col3 INT NOT NULL, col4 INT NOT NULL, UNIQUE KEY(col1, col2) ) PARTITION BY HASH(col3) PARTITIONS 4; ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function
RANGE
LIST
HASH
KEY
COLUMNS大数据
use test; -- 5.7以上版本应该没有这个库,能够自行建立 CREATE TABLE t_range ( id INT PRIMARY KEY ) ENGINE=INNODB PARTITION BY RANGE(id) ( -- 根据id划分 PARTITION p0 VALUES LESS THAN (10), -- 小于10的在p0分区 PARTITION P1 VALUES LESS THAN(20)); --大于10的在p1分区
RANGE后面必须是int类型的,若是是日期类型的须要转成int类型的,好比RANGE(year(from_date)),这样就是按年进行分区spa
LESS THAN (MAXVALUE)表示剩下的全部数据都插入到这个区间内日志
查看表结构code
show create table t\G;
看到下图这样的有PARTITION选项的就表示是一张分区表orm
同时在数据库目录下面看到了有2个ibd文件,由于这里设置了2个分区
而后运行一些插入语句
insert into t values(1); insert into t values(2); insert into t values(16); select * from t;
虽然这是一张有2个分区的分区表,可是查询的时候看到的内容仍是同样的
有个小细节,若是这个时候插入一个10,是会被分配到p1分区的,能够这样查看
insert into t values(10); explain select * from t where id = 10;
此时若是插入大于20的数据是会报错的,没法插入
insert into t values(30);
数据库不是一个二元的比较结果集(只会返回1或者0),数据库还能够返回NULL这个不肯定性的值
select NULL = NULL; -- 依旧返回NULL值 select NULL is NULL; -- 查询NULL值须要is NULL来查询
空值会致使分区有一些小小的考虑的问题,若是from_date是NULl值,会被分配到p0或者最小的分区内,由于NULL值会被做为负无穷的值(最小值)。可是推荐建立表的时候分区键为NOT NULL,建立表的时候全部字段尽可能要求也是非空的。NULL值不是一件好事情。
在mysql中NULL值和空字符串不是一个意思
CREATE TABLE t_list( a INT, b INT)ENGINE=INNODB PARTITION BY LIST(b)( PARTITION p0 VALUES IN (1,3,5,7,9), PARTITION p1 VALUES IN (0,2,4,6,8));
LIST分区很简单,13579的数据会被插入到p0分区,02468的数据会被插入到p1分区,并且有a,b两个字段的时候,插入操做的时候必须对b列的数据进行插入操做。LIST简单点说也就是指定的值插入到对应的分区,而RANGE是一个范围的值插入到对应的分区。
CREATE TABLE t_hash( a INT, b DATETIME )ENGINE=INNODB PARTITION BY HASH(YEAR(b)) PARTITIONS 4; -- 4个分区
hash分区和range分区差很少,先作一次hash,而后平均的放到这4个分区里
面。hash分区相对range分区好处是数据的分布相对来讲会比较平均一些。
CREATE TABLE t_key( a INT, b DATETIME )ENGINE=INNODB PARTITION BY KEY(b) PARTITIONS 4; -- 4个分区
相对range和hash分区,key分区对分区键不须要进行整形转换,使用KEY(b)便可。
支持全部的
整形类型(INT,SMALLINT,TINYINT,BIGINT),FLOAT和DECIMAL不支持
日期类型(DATE,DATETIME),其他不支持
字符串类型(CHAR,VARCHAR,BINARY,VARBINARY),BLOB和TEXT不支持
CREATE TABLE t_columns_range( a INT, b DATETIME ) ENGINE=INNODB PARTITION BY RANGE|LIST COLUMNS(b)( PARTITION p0 VALUES LESS THAN('2009-01-01'), PARTITION p1 VALUES LESS THAN('2010-01-01') );
COLUMNS函数的做用是不用在写其它的转换函数了
在分区的基础上再进行分区
也称为符合分区
容许在RANGE和LIST的分区上再进行HASH或者是KEY的子分区
CREATE TABLE ts (a INT, b DATE) ENGINE=INNODB PARTITION BY RANGE(YEAR(b)) SUBPARTITION BY HASH(TO_DAYS(b)) SUBPARTITIONS 2( PARTITION p0 VALUES LESS THAN(1990), PARTITION p1 VALUES LESS THAN(2000), PARTITION p2 VALUES LESS THAN MAXVALUE );
上面一共建立了3个分区表以及每一个分区表对应的2个子分区,因此在数据文件目录下你一共会看到3*2=6个相关的分区文件
实际中子分区用得并很少
用分区表用得最多的时候不是hash,是range而后使用日期进行分区,由于不少数据都是有日期属性的,这样就实现了“更小、更可管理”
清理数据的时候可能会用到这样的方法
delete from ts where b >= '2016-06-01' and b <= '2016-06-30';
若是表的数据过大的时候,这样的逻辑删除操做是比较耗时的并且会产生大量的日志,作出从同步的时候会有比较大的延时,因此这样清理数据可能并非一个很好的方法
可是若是作了分区表,能够直接直接drop partition
alert table ts drop partition p0;
实际上这个操做就是直接删除了该分区表对应的数据文件,还能够经过exchange进行数据表的交换,这样数据就显得很是灵活。
可是mysql中分区表某些场景下性能可能会很差
mysql的分区是局部分区,全部的索引只在当前分区里面的
CREATE TABLE T1( col1 INT NOT NULL, col2 DATE NOT NULL, col3 INT NOT NULL, col4 INT NOT NULL, UNIQUE KEY(col1, col2) ) PARTITION BY HASH(col3) PARTITIONS 4; 报ERROR ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function
当一张表有了惟一索引可是分区字段不是惟一索引,这里col1和col2有了惟一索引,可是想经过col3来进行分区就会报错,由于分区列必须是惟一索引的一个组成部分。
这样的例子就没问题
CREATE TABLE t1( col1 INT NOT NULL, col2 INT NOT NULL, UNIQUE KEY (col1, col2) ) PARTITION BY HASH(col2) PARTITIONS 4;
原理图,mysql只能保证1在每一个分区里保持惟一,不能保证在t1p1中也不存在1
一般用分区表最多见的场景是根据日期来进行分区,而后对日期的这个子段进行查询、数据清理、归档。
mysql一张表多大进行分区没有这一说,一千万的表和一亿的表其实只有微小的性能差距,拆成小表的好处是管理起来比较方便,能够分别alter table。可是支持了在线的online DDL的,就不会阻塞应用,一张表多大数据就没有什么区别。固然分区仍是管理比较方便的
use information_schema; select * from partitions where TABLE_NAME='titles'\G;
使用explain来查看数据所在的分区
explain select * from t where id = 10;
一个分区的时候性能相对来讲是不错的
explain select * from t where id >= 0;
用到多个分区的时候性能可能会很是糟糕
因此分区对性能有没有帮助,实际上是要看你的查询方式,若是是在多个分区中进行查询,那每一个分区表都要扫一下和只扫一个分区,性能会差很是多
explain查看分区直接显示只有在5.7里支持