MySQL分割槽總結
前言:分割槽是指根據一定的規則,資料庫把一個表分解成多個更小的,更容易管理的部分。分割槽對應用來說是完全透明的,不影響應用的業務邏輯。
MySQL分割槽的優點:
1、和單個磁碟或者檔案系統分割槽相比,可以儲存更多資料;
2、優化查詢。在Where字句中包含分割槽條件時,可以只掃描必要的一個或多個分割槽來提高查詢效率;同時在涉及 SUM() 和 COUNT() 等聚合函式的查詢時,可以容易地在每個分割槽上並行處理,最終只需要彙總所有分割槽得到的結果。
3、對於已經過期或者不需要儲存的資料,可以通過刪除與這些資料有關的分割槽來快速刪除資料。
4、跨多個磁碟來分散資料查詢,以獲得更大的查詢吞吐量。
一:概述
MySQL 支援使用大部分儲存引擎(如:MyISAM、InnoDB、Memory等)建立分割槽表,不支援使用MERGE和CSV。
MySQL分割槽型別主要包括:range分割槽、list分割槽、hash分割槽、key分割槽;
無論是那種MySQL分割槽型別,要麼分割槽表上沒有主鍵/唯一鍵,要麼分割槽表的主鍵/唯一鍵都必須包含分割槽鍵,也就是說不能使用主鍵/唯一鍵欄位之外的其他欄位分割槽。
如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
mysql> create table emp(
-> 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 ,
-> primary key(id)
-> )
-> partition by range (store_id) (
-> partition p0 values less than(10),
-> partition p1 values less than(20),
-> partition p2 values less than(30)
-> );
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function
|
去掉主鍵約束後,建立表會成功:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
mysql> create table emp(
-> 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 (store_id) (
-> partition p0 values less than(10),
-> partition p1 values less than(20),
-> partition p2 values less than(30)
-> );
Query OK, 0 rows affected (0.02 sec)
|
分割槽的名字遵循MySQL識別符號的原則。分割槽的名字不區分大小寫,如果分割槽名分別為 mypart 和 MyPart 將會被MySQL認為是同一個分割槽而報錯。
二:RANGE分割槽
按照range分割槽的表是利用取值範圍將資料分割槽,區間要連續並且不能互相重疊,使用 values less than 操作符進行分割槽定義。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
mysql> create table emp(
-> 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 (store_id) (
-> partition p0 values less than(10),
-> partition p1 values less than(20),
-> partition p2 values less than(30)
-> );
Query OK, 0 rows affected (0.02 sec)
|
如果增加商店ID大於等於30的行,超出分割槽範圍,會出現錯誤。
1 2 |
mysql> insert into emp(id,ename,hired,job,store_id) values ( '7934' , 'MILLER' , '1982-01-23' , 'CLERK' , 50);
ERROR 1526 (HY000): Table has no partition for value 50
|
可以使用 values less than maxvalue 設定分割槽,超出明確指定的分割槽值時,資料會儲存在該分割槽,如:
1 2 3 4 5 6 |
mysql> alter table emp add partition(partition p3 values less than maxvalue);
Query OK, 0 rows affected (0.25 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> insert into emp(id,ename,hired,job,store_id) values ( '7934' , 'MILLER' , '1982-01-23' , 'CLERK' , 50);
Query OK, 1 row affected (0.05 sec)
|
MySQL支援在 values less than 字句中使用表示式 partition by range (year(separated)),可自行測試。類似的函式有 to_days()、to_seconds();5.5版本後可直接使用日期欄位作為分割槽鍵。
Range分割槽特別使用的兩種情況:
1、當需要刪除過期的資料時,只需要簡單的 ALTER TABLE emp DROP PARTITION p0 來刪除p0分割槽中的資料,對於具有上百萬條記錄的表來說,刪除分割槽要比執行一個 DELETE 語句有效得多。
2、經常執行包含分割槽間的查詢,MySQL 可以很快地確定只有一個或者某些分割槽需要掃描,因為其他分割槽不可能包含有該 WHERE 字句的任何記錄。
三:List 分割槽
List 分割槽是建立離散的值列表告訴資料庫特定的值屬於哪個分割槽,List 分割槽在很多方面類似於 Range 分割槽,區別在於 List 分割槽是從屬於一個列舉列表的值得集合,Range 分割槽從屬於一個連續區間值得集合。
1 2 3 4 5 6 7 8 9 10 11 12 |
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, 10),
-> partition p2 values in (4, 9),
-> partition p3 values in (2),
-> partition p4 values in (6)
-> );
Query OK, 0 rows affected (0.05 sec)
|
如果插入的列值不包含分割槽值得列表中,insert 操作會失敗報錯。注意:List 分割槽不存在類似 values less than maxvalue 這樣包含其他值在內的定義方式。將要匹配的任何值都必須在值列表中。
四:Hash 分割槽
Hash 分割槽主要用來分散熱點讀,確保資料在預先確定個數的分割槽中儘可能平均分佈。MySQL 支援兩種 Hash 分割槽:常規 Hash 分割槽、線性 Hash 分割槽(Linear Hash 分割槽)。常規 Hash 分割槽使用的是取模演算法,線性 Hash 分割槽使用的是一個線性的2的冪的運演算法則。
1、常規 Hash 分割槽
使用 PARTITION BY HASH(expr) PARTITIONS num 字句對分割槽型別、分割槽鍵和分割槽個數進行定義,其中 expr 是某列值或一個基於某列值返回的表示式。num 是一個非負整數,表示分割槽數量,預設為1。
1 2 3 4 5 6 7 8 9 10 |
mysql> create table emp_hash(
-> 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 hash (store_id) partitions 4;
Query OK, 0 rows affected (0.03 sec)
|
假設將要儲存記錄的分割槽編號為N, 那麼 N=MOD(expr, num) 如,emp_hash表中有4個分割槽,插入一個 store_id列值為234的記錄到表中:
1 2 |
mysql> insert into emp_hash values (1, 'Tom' , '2010-10-10' , '9999-12-31' , 'Clerk' , 234);
Query OK, 1 row affected (0.01 sec)
|
MOD(234, 4)=2 儲存這條記錄的分割槽應該是p2;從p0 開始,模為 0 時儲存到 p0 依次類推。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
mysql> explain partitions select * from emp_hash where store_id =234\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: emp_hash
partitions: p2
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref : NULL
rows: 2
Extra: Using where
1 row in set (0.05 sec)
|
不推薦使用涉及多列的雜湊表示式,複雜的表示式可能會引起效能問題。常規 Hash 在分割槽管理上需要的代價高,不適合需要靈活變動分割槽的需求。
2、線性 Hash 分割槽(Linear Hash)
線性 Hash 分割槽和常規 Hash 分割槽 在語法上的唯一區別是在 partition by 字句中新增關鍵字 “Linear”,如:
1 2 3 4 5 6 7 8 9 10 |
mysql> create table emp_linear(
-> 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 linear hash (store_id) partitions 4;
Query OK, 0 rows affected (0.03 sec)
|
線性Hash分割槽的優點是:在分割槽維護(增加、刪除、合併、拆分分割槽時),MySQL能夠處理得更加迅速;缺點是:對比常規的Hash分割槽(取模)的時候,線性Hash各個分割槽之間資料的分佈不太均衡。
五:Key 分割槽
Key 分割槽類似於 Hash 分割槽,不過 Key 分割槽不允許使用使用者自定義的表示式,需要使用 MySQL 伺服器提供的 Hash 函式;同時 Hash 分割槽只支援整數分割槽,而 Key 分割槽支援使用 Blob 或 Text 型別外其他型別的列作為分割槽鍵
1 2 3 4 5 6 7 8 9 10 |
mysql> create table emp_key(
-> 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 key (job) partitions 4;
Query OK, 0 rows affected (0.05 sec)
|
建立 Key 分割槽表的時候,可以不指定分割槽鍵,預設會首先選擇使用主鍵作為分割槽鍵
1 2 3 4 5 6 7 8 9 10 |
mysql> create table emp_key1(
-> 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 key () partitions 4;
Query OK, 0 rows affected (0.03 sec)
|
在沒有主鍵的情況,會選擇非空唯一鍵作為分割槽鍵,分割槽鍵的唯一鍵必須是非空的,如果不是非空會報錯:
1 2 3 4 5 6 7 8 9 10 11 |
mysql> create table emp_key2(
-> 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 ,
-> unique key(id)
-> )
-> partition by key () partitions 4;
Query OK, 0 rows affected (0.03 sec)
|
和 Hash 分割槽類似,在 Key 分割槽中使用關鍵字 Linear 具有同樣的作用,Linear Key 分割槽時,分割槽的編號是通過2的冪演算法得到的,不是通過取模得到的。
附:MySQL 分割槽的 null 值處理
1、MySQL 分割槽不禁止在分割槽鍵值上使用 null
2、Range 分割槽中,null 值會被當做最小值來處理
3、List 分割槽中,null 值必須出現在列舉列表中,否則不被接受
4、Hash/Key 分割槽中,null 值會被當做零值來處理
5、為了避免在處理 null 值時出現誤判,推薦通過設定欄位非空和預設值來繞開 MySQL 對 null 值的預設處理