MySQL分區總結
前言:分區是指根據一定的規則,數據庫把一個表分解成多個更小的,更容易管理的部分。分區對應用來說是完全透明的,不影響應用的業務邏輯。
MySQL分區的優點:
1、和單個磁盤或者文件系統分區相比,可以存儲更多數據;
2、優化查詢。在Where字句中包含分區條件時,可以只掃描必要的一個或多個分區來提高查詢效率;同時在涉及 SUM() 和 COUNT() 等聚合函數的查詢時,可以容易地在每個分區上並行處理,最終只需要匯總所有分區得到的結果。
3、對於已經過期或者不需要保存的數據,可以通過刪除與這些數據有關的分區來快速刪除數據。
4、跨多個磁盤來分散數據查詢,以獲得更大的查詢吞吐量。
一:概述
MySQL 支持使用大部分存儲引擎(如:MyISAM、InnoDB、Memory等)創建分區表,不支持使用MERGE和CSV。 MySQL分區類型主要包括:range分區、list分區、hash分區、key分區;無論是那種MySQL分區類型,要麽分區表上沒有主鍵/唯一鍵,要麽分區表的主鍵/唯一鍵都必須包含分區鍵,也就是說不能使用主鍵/唯一鍵字段之外的其他字段分區。如:
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
去掉主鍵約束後,創建表會成功:
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 操作符進行分區定義。
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的行,超出分區範圍,會出現錯誤。
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 設置分區,超出明確指定的分區值時,數據會存儲在該分區,如:
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 分區從屬於一個連續區間值得集合。
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。
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的記錄到表中:
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 依次類推。
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”,如:
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 類型外其他類型的列作為分區鍵
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 分區表的時候,可以不指定分區鍵,默認會首先選擇使用主鍵作為分區鍵
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)
在沒有主鍵的情況,會選擇非空唯一鍵作為分區鍵,分區鍵的唯一鍵必須是非空的,如果不是非空會報錯:
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 值的默認處理
MySQL分區總結