將一個表或者索引分解爲多個更小、更可管理的部分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裏支持