17.Mysql分區
17.Mysql分區
分區是指根據一定的規則把一個表分解成多個部分,邏輯上仍是一張表,實際上由多個物理分區對象組成。
分區對於應用是完全透明的,不影響業務邏輯和SQL編寫。
分區的優點:
可以存儲更多的數據;
優化查詢;當where條件包含分區鍵時只在特定的分區查詢;當涉及聚合函數時每個分區可以並行查詢。
可以通過分區快速刪除過期數據;
可以將不同的分區分散在多個磁盤上,獲取更高的磁盤IO。
17.1 分區概述
分區使用分區鍵對某個列的取值進行範圍、列表、HASH值劃分,從而將表中的數據劃分到為不同的分區。
查看當前Mysql是否支持分區:
show variables like ‘%partition%‘;
同一個表的所有分區必須使用相同的存儲引擎;
不同的分區表可以使用不同的存儲引擎。
例子:
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類型。
在有主鍵列的表中,主鍵列必須作為分區鍵;
語法:
create table 表名 (
列名 類型(長度) 約束,
...
)
partition by range (列表達式) (
partition 分區名1 values less than (列值1),
...
[partition 分區名n values less than MAXVALUE]
);
說明:
列值區間必須連續,且不能重疊;
分區名不區分大小寫,且不能重復;
列值區間為前閉後開[),即包含左側,不包含右側;
插入值不在所有區間內,插入將報錯;
MAXVALUE為默認最大值,設置MAXVALUE分區後將不能再擴展分區;
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 小結
17.Mysql分區