MySQL 分割槽表
目錄
MySQL分割槽就是將一個表分解為多個更小的表。從邏輯上講,只有一個表或一個索引,但在物理上這個表或者索引可能由多個物理分割槽組成。每個分割槽在物理上都是獨立的。MySQL資料庫分割槽型別:
- Range分割槽:行資料基於屬於一個給定連續區間的列值放入分割槽。
- List分割槽:和Range分割槽類似,只是List分割槽面向的是離散的值。
- Hash分割槽:根據使用者自定義的表示式的返回值來進行分割槽,返回值不能為負數。
- Key分割槽:根據MySQL資料庫提供的雜湊函式來進行分割槽。
- Columns分割槽:Range分割槽和List分割槽的擴充套件,支援非整型的分割槽條件。
- 子分割槽(複合分割槽):MySQL資料庫允許在Range和List的分割槽上再進行Hash或者Key的子分割槽。
不論建立何種型別的分割槽,如果表中存在主鍵或唯一索引時,分割槽列必須是唯一索引的一個組成部分。
1. Range分割槽
用法示例:
create table t_range( id int) engine=innodb partition by range(id) ( partition p0 values less than (10), partition p1 values less than (20), partition p2 values less than maxvalue);
上面例子表示建立了一個id列的區間分割槽表,當id<10時,資料會插入p0分割槽。當10<=id<20時,資料會插入p0分割槽,id>=20時,資料會插入p2分割槽。maxvalue
表示正無窮大。分割槽表會在磁碟上為每個分割槽建立一個檔案,如下:
# ls -lh t_range* -rw-r----- 1 mysql mysql 8.4K 8月 17 19:25 t_range.frm -rw-r----- 1 mysql mysql 96K 8月 17 19:25 t_range#P#p0.ibd -rw-r----- 1 mysql mysql 96K 8月 17 19:25 t_range#P#p1.ibd -rw-r----- 1 mysql mysql 96K 8月 17 19:25 t_range#P#p2.ibd
插入幾條資料,檢視資料在各分割槽的分佈情況:
mysql> insert into t_range values (1), (2), (10), (15), (16), (20), (22), (24), (25);
Query OK, 9 rows affected (0.10 sec)
Records: 9 Duplicates: 0 Warnings: 0
mysql> select * from information_schema.partitions where table_schema=database() and table_name='t_range'\G
*************************** 1. row ***************************
TABLE_CATALOG: def
TABLE_SCHEMA: mytest
TABLE_NAME: t_range
PARTITION_NAME: p0
SUBPARTITION_NAME: NULL
PARTITION_ORDINAL_POSITION: 1
SUBPARTITION_ORDINAL_POSITION: NULL
PARTITION_METHOD: RANGE
SUBPARTITION_METHOD: NULL
PARTITION_EXPRESSION: id
SUBPARTITION_EXPRESSION: NULL
PARTITION_DESCRIPTION: 10
TABLE_ROWS: 2
AVG_ROW_LENGTH: 8192
DATA_LENGTH: 16384
MAX_DATA_LENGTH: NULL
INDEX_LENGTH: 0
DATA_FREE: 0
CREATE_TIME: 2020-08-17 19:25:02
UPDATE_TIME: 2020-08-17 19:40:16
CHECK_TIME: NULL
CHECKSUM: NULL
PARTITION_COMMENT:
NODEGROUP: default
TABLESPACE_NAME: NULL
*************************** 2. row ***************************
TABLE_CATALOG: def
TABLE_SCHEMA: mytest
TABLE_NAME: t_range
PARTITION_NAME: p1
SUBPARTITION_NAME: NULL
PARTITION_ORDINAL_POSITION: 2
SUBPARTITION_ORDINAL_POSITION: NULL
PARTITION_METHOD: RANGE
SUBPARTITION_METHOD: NULL
PARTITION_EXPRESSION: id
SUBPARTITION_EXPRESSION: NULL
PARTITION_DESCRIPTION: 20
TABLE_ROWS: 3
AVG_ROW_LENGTH: 5461
DATA_LENGTH: 16384
MAX_DATA_LENGTH: NULL
INDEX_LENGTH: 0
DATA_FREE: 0
CREATE_TIME: 2020-08-17 19:25:02
UPDATE_TIME: 2020-08-17 19:40:16
CHECK_TIME: NULL
CHECKSUM: NULL
PARTITION_COMMENT:
NODEGROUP: default
TABLESPACE_NAME: NULL
*************************** 3. row ***************************
TABLE_CATALOG: def
TABLE_SCHEMA: mytest
TABLE_NAME: t_range
PARTITION_NAME: p2
SUBPARTITION_NAME: NULL
PARTITION_ORDINAL_POSITION: 3
SUBPARTITION_ORDINAL_POSITION: NULL
PARTITION_METHOD: RANGE
SUBPARTITION_METHOD: NULL
PARTITION_EXPRESSION: id
SUBPARTITION_EXPRESSION: NULL
PARTITION_DESCRIPTION: MAXVALUE
TABLE_ROWS: 4
AVG_ROW_LENGTH: 4096
DATA_LENGTH: 16384
MAX_DATA_LENGTH: NULL
INDEX_LENGTH: 0
DATA_FREE: 0
CREATE_TIME: 2020-08-17 19:25:02
UPDATE_TIME: 2020-08-17 19:40:16
CHECK_TIME: NULL
CHECKSUM: NULL
PARTITION_COMMENT:
NODEGROUP: default
TABLESPACE_NAME: NULL
3 rows in set (0.00 sec)
PARTITION_METHOD表示分割槽型別,TABLE_ROWS列表示分割槽中記錄的數量,可以看到p0分割槽有2條記錄,p1分割槽有3條記錄,p2分割槽有4條記錄。
2. List分割槽
List分割槽和Range分割槽相似,只是分割槽列是離散的。用法如下:
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分割槽表是,同一個數值不能出現兩次,否則會報錯ERROR 1495 (HY000): Multiple definition of same constant in list partitioning
。
3. Hash分割槽
Hash分割槽的目的是將資料均勻地分佈到預先定義地各個分割槽中,保證各分割槽地資料數量大致都是一樣的。在Range和List分割槽中,必須明確指定一個給定的列值或列值集合應該儲存在哪個分割槽,而在Hash分割槽中,MySQL自動完成這些工作,我們所要做的只是基於將要被雜湊的列值指定一個列值或表示式,以及指定被分割槽的表將要被分割成的分割槽數量。
Hash分割槽表用法如下:以YEAR(b)做hash,分割槽資料量是4。
create table t_hash (
a int,
b datetime) engine=innodb
partition by hash (YEAR(b))
partitions 4;
MySQL還支援一種稱為Linear Hash的分割槽,它的用法跟Hash分割槽一樣,只是將關鍵字Hash改為Linear Hash。Linear Hash分割槽使用了一個更加複雜的演算法來做hash函式。Linear Hash分割槽的優點在於增加、刪除、合併、拆分分割槽效率更高,有利於處理資料量大的表;缺點是資料分佈不大均衡。
4. Key分割槽
Key分割槽和Hash分割槽相似,不同在於,Hash分割槽使用使用者指定的函式進行分割槽,Key分割槽無需明確指定函式,會自動使用MySQL資料庫提供的函式進行分割槽。Key分割槽也可以使用關鍵字Linear。用法如下:
create table t_key (
a int,
b datetime) engine=innodb
partition by key (b)
partitions 4;
5. Columns分割槽
Range、List、Hash、Key這四種分割槽中,分割槽的條件必須是整型,如果不是整型,需要通過Year()、Month()等函式將其轉化為整型。Columns分割槽可以直接使用非整型的資料進行分割槽,分割槽根據型別直接比較而得,不需要轉化為整型。Range Columns分割槽還可以對多個列的值進行分割槽。Columns分割槽支援:所有整型、日期型別(Date、Datetime)、字串型別(Blob、Text不支援)。用法如下:
create table t_columus_range(
a int,
b datetime) engine=innodb
partition by range columns (b) (
partition p0 values less than ('2019-01-01'),
partition p1 values less than ('2020-01-01'));
# 使用多個列進行分割槽
create table t_range_columns_mult (
a int,
b int,
c char(3),
d int) engine=innodb
partition by range columns (a,b,c)(
partition p0 values less than (5, 10, 'sdd'),
partition p1 values less than (10, 20, 'xxx'),
partition p2 values less than (maxvalue, maxvalue, maxvalue));
6. 子分割槽
子分割槽是在分割槽的基礎上再進行分割槽,也稱複合分割槽。MySQL允許在Range和List的分割槽上再進行Hash或Key的子分割槽。用法如下:
# 一下只指定了每個分割槽的子分割槽數量為2,沒有指定每個分割槽的名稱。
create table t_sub (
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);
# 看下物理上的分佈
ls -lh t_sub*
-rw-r----- 1 mysql mysql 8.4K 8月 18 11:46 t_sub.frm
-rw-r----- 1 mysql mysql 96K 8月 18 11:46 t_sub#P#p0#SP#p0sp0.ibd
-rw-r----- 1 mysql mysql 96K 8月 18 11:46 t_sub#P#p0#SP#p0sp1.ibd
-rw-r----- 1 mysql mysql 96K 8月 18 11:46 t_sub#P#p1#SP#p1sp0.ibd
-rw-r----- 1 mysql mysql 96K 8月 18 11:46 t_sub#P#p1#SP#p1sp1.ibd
-rw-r----- 1 mysql mysql 96K 8月 18 11:46 t_sub#P#p2#SP#p2sp0.ibd
-rw-r----- 1 mysql mysql 96K 8月 18 11:46 t_sub#P#p2#SP#p2sp1.ibd
# 也可以顯示指定每個子分割槽的名稱
create table t_sub_named (
a int,
b date) engine = innodb
partition by range(year(b))
subpartition by hash(to_days(b))(
partition p0 values less than (1990) (
subpartition s0,
subpartition s1),
partition p1 values less than (2000) (
subpartition s2,
subpartition s3),
partition p2 values less than maxvalue(
subpartition s4,
subpartition s5));
子分割槽的建立需要注意以下幾個問題:
- 每個分割槽下的子分割槽的數量必須相同。
- 如果在分割槽表的任何分割槽上使用
subpartition
來明確定義任何子分割槽,那麼就必須定義所有的子分割槽。 - 可以使用
subpartitions
只指定子分割槽的數量,MySQL會自動為每個子分割槽分配名稱。如果使用了subpartition
,則每個subpartition字句都必須包括子分割槽的名稱,且每個子分割槽的名稱必須唯一。
7. 分割槽中的NULL值
MySQL允許對NULL值做分割槽,並且會把NULL值視為小於任何一個非NULL值。
- 對於Range分割槽,NULL值會被插入最左邊的分割槽。
- 對於List分割槽,必須顯示指出NULL值放入哪個分割槽。
- 對於Hash和Key分割槽,任何分割槽函式都會將含有NULL值的記錄返回為0。