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裏支持

相關文章
相關標籤/搜索