1. 程式人生 > 實用技巧 >MySQL 分割槽表

MySQL 分割槽表

目錄

  MySQL分割槽就是將一個表分解為多個更小的表。從邏輯上講,只有一個表或一個索引,但在物理上這個表或者索引可能由多個物理分割槽組成。每個分割槽在物理上都是獨立的。MySQL資料庫分割槽型別:

  1. Range分割槽:行資料基於屬於一個給定連續區間的列值放入分割槽。
  2. List分割槽:和Range分割槽類似,只是List分割槽面向的是離散的值。
  3. Hash分割槽:根據使用者自定義的表示式的返回值來進行分割槽,返回值不能為負數。
  4. Key分割槽:根據MySQL資料庫提供的雜湊函式來進行分割槽。
  5. Columns分割槽:Range分割槽和List分割槽的擴充套件,支援非整型的分割槽條件。
  6. 子分割槽(複合分割槽):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。