mysql笔记 - 分区表

分区表概念

将一个表或者索引分解为多个更小、更可管理的部分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大数据

RANGE分区

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选项的就表示是一张分区表
clipboard.pngorm

同时在数据库目录下面看到了有2个ibd文件,由于这里设置了2个分区
clipboard.png

而后运行一些插入语句

insert into t values(1);
insert into t values(2);
insert into t values(16);
select * from t;

虽然这是一张有2个分区的分区表,可是查询的时候看到的内容仍是同样的
clipboard.png

有个小细节,若是这个时候插入一个10,是会被分配到p1分区的,能够这样查看

insert into t values(10);
explain select * from t where id = 10;

clipboard.png

此时若是插入大于20的数据是会报错的,没法插入

insert into t values(30);

clipboard.png

特殊数据类型NULL值

数据库不是一个二元的比较结果集(只会返回1或者0),数据库还能够返回NULL这个不肯定性的值

select NULL = NULL; -- 依旧返回NULL值
select NULL is NULL; -- 查询NULL值须要is NULL来查询

空值会致使分区有一些小小的考虑的问题,若是from_date是NULl值,会被分配到p0或者最小的分区内,由于NULL值会被做为负无穷的值(最小值)。可是推荐建立表的时候分区键为NOT NULL,建立表的时候全部字段尽可能要求也是非空的。NULL值不是一件好事情。

在mysql中NULL值和空字符串不是一个意思
clipboard.png

LIST分区

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是一个范围的值插入到对应的分区。

HASH分区

CREATE TABLE t_hash(
    a INT,
    b DATETIME
)ENGINE=INNODB
PARTITION BY HASH(YEAR(b))
PARTITIONS 4; -- 4个分区

hash分区和range分区差很少,先作一次hash,而后平均的放到这4个分区里

面。hash分区相对range分区好处是数据的分布相对来讲会比较平均一些。

KEY分区

CREATE TABLE t_key(
    a INT,
    b DATETIME
)ENGINE=INNODB
PARTITION BY KEY(b)
PARTITIONS 4; -- 4个分区

相对range和hash分区,key分区对分区键不须要进行整形转换,使用KEY(b)便可。

COLUMNS分区 5.5版本加持

支持全部的

  • 整形类型(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个相关的分区文件
clipboard.png

实际中子分区用得并很少

更可管理

用分区表用得最多的时候不是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
clipboard.png

性能

一般用分区表最多见的场景是根据日期来进行分区,而后对日期的这个子段进行查询、数据清理、归档。

mysql一张表多大进行分区没有这一说,一千万的表和一亿的表其实只有微小的性能差距,拆成小表的好处是管理起来比较方便,能够分别alter table。可是支持了在线的online DDL的,就不会阻塞应用,一张表多大数据就没有什么区别。固然分区仍是管理比较方便的

查询每一个分区的记录数量

use information_schema;
select * from partitions where TABLE_NAME='titles'\G;

clipboard.png

使用explain来查看数据所在的分区

explain select * from t where id = 10;

一个分区的时候性能相对来讲是不错的
clipboard.png

explain select * from t where id >= 0;

用到多个分区的时候性能可能会很是糟糕
clipboard.png

因此分区对性能有没有帮助,实际上是要看你的查询方式,若是是在多个分区中进行查询,那每一个分区表都要扫一下和只扫一个分区,性能会差很是多

explain查看分区直接显示只有在5.7里支持

相关文章
相关标签/搜索