17.Mysql分割槽
17.Mysql分割槽
分割槽是指根據一定的規則把一個表分解成多個部分,邏輯上仍是一張表,實際上由多個物理分割槽物件組成。
分割槽對於應用是完全透明的,不影響業務邏輯和SQL編寫。
分割槽的優點:
可以儲存更多的資料;
優化查詢;當where條件包含分割槽鍵時只在特定的分割槽查詢;當涉及聚合函式時每個分割槽可以並行查詢。
可以通過分割槽快速刪除過期資料;
可以將不同的分割槽分散在多個磁碟上,獲取更高的磁碟IO。
17.1 分割槽概述
分割槽使用分割槽鍵對某個列的取值進行範圍、列表、HASH值劃分,從而將表中的資料劃分到為不同的分割槽。
檢視當前Mysql是否支援分割槽:
show variables like '%partition%';
Mysql分割槽由具體的儲存引擎實現,只有部分儲存引擎(Innodb)支援分割槽。
同一個表的所有分割槽必須使用相同的儲存引擎;
不同的分割槽表可以使用不同的儲存引擎。
例子:
create table temp (empid int,salary decimal(7,2),birth_date date)
engine=innodb
partition by hash(month(birth_date)) partitions 4;
17.2 分割槽型別
17.2.1 Range分割槽
Range分割槽:基於一個給定列的取值的連續範圍進行分割槽。分割槽鍵必須是INT型別。
在有主鍵列的表中,主鍵列必須作為分割槽鍵;
在沒有主鍵列的表中,INT型別列可以作為分割槽鍵,非INT型別列經過表示式處理後轉換為INT型別也可以作為分割槽鍵。
語法:
create table 表名 (
列名 型別(長度) 約束,
...
)
partition by range (列表達式) (
partition 分割槽名1 values less than (列值1),
...
[partition 分割槽名n values less than MAXVALUE]
);
說明:
列值區間必須連續,且不能重疊;
分割槽名不區分大小寫,且不能重複;
列值區間為前閉後開[),即包含左側,不包含右側;
插入值不在所有區間內,插入將報錯;
MAXVALUE為預設最大值,設定MAXVALUE分割槽後將不能再擴充套件分割槽;
如果列是非INT型別,可使用函式、表示式將列轉為INT型別,也可以使用range columns分割槽。
range columns分割槽支援對日期列和字元列進行分割槽。
如果分割槽鍵列為null,將被當作最小值處理。
例子1:
create table temp (empid int,salary decimal(7,2),birth_date date)
partition by range(year(birth_date)) (
partition p1 values less than (1990),
partition p2 values less than (2000),
partition p3 values less than (2010)
);
例子2:
create table temp (empid int,salary decimal(7,2),birth_date date)
partition by range columns(birth_date) (
partition p1 values less than ('1990-01-01'),
partition p2 values less than ('2000-01-01'),
partition p3 values less than ('2010-01-01')
);
查詢SQL:
explain parttions select count(1) from temp where birth_date>='2000-01-01';
17.2.2 List分割槽
List分割槽:基於一個給定列的取值的列舉值進行分割槽。分割槽鍵必須是INT型別。
在有主鍵列的表中,主鍵列必須作為分割槽鍵;
在沒有主鍵列的表中,INT型別列可以作為分割槽鍵,非INT型別列經過表示式處理後轉換為INT型別也可以作為分割槽鍵。
語法:
create table 表名 (
列名 型別(長度) 約束,
...
)
partition by list (列表達式) (
partition 分割槽名1 values in (整數列表),
...
);
說明:
整數列表是列的一個或多個取值,多個值時用逗號分隔;
整數列表取值與順序無關;
插入值不在所有區間內,插入將報錯;
如果列是非INT型別,可使用函式、表示式將列轉為INT型別,也可以使用list columns分割槽。
list columns分割槽支援對日期列和字元列進行分割槽。
例子1:
create table temp (empid int,category int,birth_date date)
partition by list(category) (
partition p1 values in (1,3),
partition p2 values in (5,2),
partition p3 values in (4)
);
例子2:
create table temp (empid int,category varchar(10),birth_date date)
partition by list columns(category) (
partition p1 values in ('高中','大專'),
partition p2 values in ('本科'),
partition p3 values in ('碩士','博士')
);
17.2.3 Range/List Columns分割槽
Range/List Columns分割槽是Range分割槽和List分割槽的增強,區別在於分割槽鍵可以是整數、日期、字串型別。
Range/List Columns分割槽的分割槽鍵支援的資料型別包括:
整數型別(tinyint、smallint、mediumint、int、bigint),日期時間型別(date、datetime),字元型別(char、varchar、binary、varbinary)。
Range/List Columns分割槽的分割槽鍵不支援的資料型別包括:浮點型別(decimal、float)、大物件型別(blob、text)。
Range/List Columns分割槽不支援列表達式分割槽,只能使用原始列。
Range/List Columns分割槽支援多個列組合分割槽,多列組合分割槽時將基於元組進行比較,即進行多列排序根據排序結果來選擇分割槽。
例子1:
create table test(
a int,
b int
)
partition by range columns(a,b) (
partition p01 values less than (0,10),
partition p02 values less than (10,10),
partition p03 values less than (10,20),
partition p04 values less than (20,20)
);
17.2.4 Hash分割槽
Hash分割槽:基於一個給定列的取值的HASH函式進行分割槽。分割槽鍵必須是INT型別。
Hash分割槽可以用來分散熱點讀,並確保資料在預先確定個數的分割槽中儘可能的均勻分佈。
Hash分割槽分為常規Hash分割槽和線性Hash分割槽(Linear hash),常規Hash分割槽採用取模演算法,線性Hash分割槽採用2的冪運演算法則。
例子1:
create table test(
a int,
b int
)
partition by hash(a) partitions 3;
對a列的數值取除以3的餘數,餘數為0/1/2,分別對應在一個分割槽中。
常規Hash分割槽不支援新增分割槽、合併分割槽等分割槽管理操作。
例子2:
create table test(
a int,
b int
)
partition by linear hash(a) partitions 4;
線性Hash分割槽建議分割槽個數是2的冪次個,否則將導致資料分佈不均勻。
首先找到大於等於分割槽個數的2的冪次,V=power(2,ceiling(log(2,分割槽個數)));
其次將列值和(V-1)進行按位與操作。
線性Hash分割槽支援分割槽管理操作,包括:增加分割槽、刪除分割槽、合併分割槽、拆分分割槽。
17.2.5 Key分割槽
Key分割槽是Hash分割槽的增強,區別在於分割槽鍵可以任何型別(除大物件型別BLOB和TEXT)。
Key分割槽是支援整數、日期、字元型別的Hash分割槽,但不支援表示式。
例子1:
create table test(
a int,
b int
)
partition by key(a) partitions 4;
注意:
不指定分割槽鍵列時預設使用主鍵列,沒有主鍵時預設非空的唯一鍵列;
不指定分割槽鍵列且沒有主鍵時,唯一鍵列可空將報錯;
沒有主鍵、唯一鍵時,必須指定分割槽鍵列。
例子2:
create table test(
a int,
b int
)
partition by linear key(a) partitions 4;
注意:Key分割槽同樣支援常規Key分割槽和線性key分割槽。
17.2.6 子分割槽
子分割槽(subpartitioning)是對分割槽表的再次分割槽,又稱複合分割槽。
可以對Range分割槽和List分割槽再次進行分割槽,子分割槽可以是hash分割槽或key分割槽。
例子:
create table temp (empid int,salary decimal(7,2),birth_date date)
partition by range columns(birth_date)
subpartition by hash(empid) subpartitions 2
(
partition p1 values less than ('1990-01-01'),
partition p2 values less than ('2000-01-01'),
partition p3 values less than ('2010-01-01')
);
17.2.7 mysql分割槽處理null值的方式
mysql允許可空列作為分割槽鍵。
Range分割槽中null值被當作最小值處理,始終在第一個分割槽中;
List分割槽中null值必須出現在列舉列表中(否則報錯),可以自行定義null值在哪個分割槽中;
hash分割槽中null值被當作0處理,始終在第一個分割槽中。
建議分割槽鍵設定為非空。
分割槽資訊在information_schema.partitions表中記錄。
17.3 分割槽管理
17.3.1 Range和List分割槽管理
增加分割槽:
alter table 表名 add partition (partition 分割槽名 values less than (列值));
alter table 表名 add partition (partition 分割槽名 values in (列值列表));
注意:
Range分割槽新增分割槽時必須保證列值與已有列值連續且有序;
List分割槽新增分割槽時必須保證列值列表與已有列值列表不重複。
刪除分割槽:刪除分割槽的同時會刪除分割槽內的資料。
alter table 表名 drop partition 分割槽名;
重定義分割槽:可以將一個分割槽拆分為多個分割槽;也可以將相鄰多個分割槽合併為一個分割槽。
重定義分割槽只能重新定義相鄰的分割槽,且分割槽區間必須能夠覆蓋原來的分割槽區間,且不能改變分割槽型別。
拆分分割槽:
alter table 表名 reorganize partition 原分割槽名 into (
partition 現分割槽名1 values less than (新區間列值),
partition 現分割槽名2 values less than (等於原列值)
);
合併分割槽:
alter table 表名 reorganize partition 原分割槽名1,原分割槽名2 into (
partition 現分割槽名1 values less than (等於原分割槽名2列值)
);
alter table 表名 reorganize partition 原分割槽名1,原分割槽名2 into (
partition 現分割槽名1 values in (新列值列表1),
partition 現分割槽名2 values in (新列值列表2)
);
注意:重組前後總的列值列表要相等,每個分割槽的列值列表可以調整。
17.3.2 Hash和Key分割槽管理
增加分割槽:
alter table 表名 add partition partitions 新增的分割槽個數;
減少分割槽:
alter table 表名 coalesce partition 減少到幾個分割槽;
17.4 小結