Mysql系列之分區

分區功能並不是存儲引擎來完成的, 因此不是隻有InnoDB纔有分區功能,MyISAM,NDB等都支持分區功能,但也並不是所有的引擎都支持,如:CSV就不支持。在使用分區功能之前,應對存儲引擎有所瞭解。

分區表


概述

MySQL數據庫在5.1版本時就添加了對分區的支持,Mysql表分區類型的水平分區,不是垂直分區,此外,MySQL數據庫的分區是局部索引,一個分區中及存放的數據又存放了索引。而全局分區是指數據存放在各個分區中,但是所有數據放在一個對象中。目前,Mysql並不支持全局分區。

爲什麼要進行分區

爲了改善大型表以及具有各種訪問模式的表的可伸縮性,可管理性和提高數據庫效率。

  • 分區的一些優點包括:

    • 與單個磁盤或文件系統分區相比,可以存儲更多的數據。
    • 對於那些已經失去保存意義的數據,通常可以通過刪除與那些數據有關的分區,很容易地刪除那些數據。相反地,在某些情況下,添加新數據的過程又可以通過爲那些新數據專門增加一個新的分區,來很方便地實現。通常和分區有關的其他優點包括下面列出的這些。MySQL分區中的這些功能目前還沒有實現,但是在我們的優先級列表中,具有高的優先級;我們希望在5.1的生產版本中,能包括這些功能。
    • 一些查詢可以得到極大的優化,這主要是藉助於滿足一個給定WHERE語句的數據可以只保存在一個或多個分區內,這樣在查找時就不用查找其他剩餘的分區。因爲分區可以在創建了分區表後進行修改,所以在第一次配置分區方案時還不曾這麼做時,可以重新組織數據,來提高那些常用查詢的效率。
    • 涉及到例如SUM()和COUNT()這樣聚合函數的查詢,可以很容易地進行並行處理。這種查詢的一個簡單例子如 “SELECT salesperson_id, COUNT (orders) as order_total FROM sales GROUP BY salesperson_id;”。通過“並行”,這意味着該查詢可以在每個分區上同時進行,最終結果只需通過總計所有分區得到的結果。
    • 通過跨多個磁盤來分散數據查詢,來獲得更大的查詢吞吐量。

分區的類型介紹

  • RANGE分區
    • 行數據基於屬於一個給定連續區間的列值被放入分區。
  • LIST分區
    • LIST分區是面向離散的值。
  • HASH分區
    • 根據用戶自定義的表達式的返回值來進行分區,返回值不能是負數
  • KEY分區
    • 根據Mysql數據庫提供的哈希函數來進行分區。

無論創建何種類型的分區,如果表中存在主鍵或唯一索引時,分區列必須是唯一索引的一個組成部分,否則會報如下錯誤:

mysql> create  table t1(
    -> col1 int not null,
    -> col2 date not null ,
    -> col3 int not null,
    -> unique key (col1, col2)
    -> )partition by hash(col3)
    -> partitions 4;
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function

唯一索引是允許爲NULL的,並且分區列只要是唯一索引的組成部分,不需要整個唯一索引都是分區列:

mysql> create  table t1(
    -> col1 int not null,
    -> col2 date not null ,
    -> col3 int not null,
    -> unique key (col1, col2, col3)
    -> )partition by hash(col3)
    -> partitions 4;
Query OK, 0 rows affected (0.07 sec)

注:如果在創建分區表的時候,沒有指定唯一字段或主鍵時,指定任何一個字段爲分區字段都是被允許的。

RANGE分區

RANGE分區是最常見的一種分區類型。

mysql> create table t(
    -> id int
    -> )engine=innodb
    -> partition by range(id) -- 給誰設置分區
    -> (
    -> partition p0 values less than (10), -- 存入該分區的條件(id值0-10    -> partition p1 values less than (20),-- 存入該分區的條件(id值10-20    -> )
    -> ;
Query OK, 0 rows affected (0.03 sec)

查看一下RANGE分區創建的系統分區

mysql> show variables like "datadir";
+---------------+--------------------------------------+
| Variable_name | Value                                |
+---------------+--------------------------------------+
| datadir       | /var/lib/mysql/                      |
+---------------+--------------------------------------+
1 row in set (0.00 sec)

mysql> system ls -lh  /var/lib/mysql/odp/t*
-rw-rw----  1 chenyang chenyang 8.5K Jul  2 14:30 /var/lib/mysql/odp/t1.frm
-rw-rw----  1 chenyang chenyang   32 Jul  2 14:30 /var/lib/mysql/odp/t1.par
-rw-rw----  1 chenyang chenyang  96K Jul  2 14:30 /var/lib/mysql/odp/t1#P#p0.ibd
-rw-rw----  1 chenyang chenyang  96K Jul  2 14:30 /var/lib/mysql/odp/t1#P#p1.ibd
-rw-rw----  1 chenyang chenyang 8.4K Jul  2 14:40 /var/lib/mysql/odp/t.frm
-rw-rw----  1 chenyang chenyang   28 Jul  2 14:40 /var/lib/mysql/odp/t.par
-rw-rw----  1 chenyang chenyang  96K Jul  2 14:40 /var/lib/mysql/odp/t#P#p0.ibd
-rw-rw----  1 chenyang chenyang  96K Jul  2 14:40 /var/lib/mysql/odp/t#P#p1.ibd

我們可以看到,表的文件不再是ibd文件組成,而是有建立分區時各個分區的ibd文件組成,如:t1#P#p0.ibd

查看RANGE分區情況

mysql> select * from information_schema.PARTITIONS where table_schema=database() and table_name='t'\G;
*************************** 1. row ***************************
                TABLE_CATALOG: def
                 TABLE_SCHEMA: odp -- 數據庫名
                   TABLE_NAME: t   -- 表名
               PARTITION_NAME: p1  -- 分區名
            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: 0   -- 數據條數
               AVG_ROW_LENGTH: 0
                  DATA_LENGTH: 16384
              MAX_DATA_LENGTH: NULL
                 INDEX_LENGTH: 0
                    DATA_FREE: 0
                  CREATE_TIME: 2018-07-02 14:40:27
                  UPDATE_TIME: NULL
                   CHECK_TIME: NULL
                     CHECKSUM: NULL
            PARTITION_COMMENT: 
                    NODEGROUP: default
              TABLESPACE_NAME: NULL
*************************** 2. row ***************************
                TABLE_CATALOG: def
                 TABLE_SCHEMA: odp -- 數據庫名
                   TABLE_NAME: t   -- 表名
               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: 0   -- 數據條數
               AVG_ROW_LENGTH: 0
                  DATA_LENGTH: 16384
              MAX_DATA_LENGTH: NULL
                 INDEX_LENGTH: 0
                    DATA_FREE: 0
                  CREATE_TIME: 2018-07-02 14:40:27
                  UPDATE_TIME: NULL
                   CHECK_TIME: NULL
                     CHECKSUM: NULL
            PARTITION_COMMENT: 
                    NODEGROUP: default
              TABLESPACE_NAME: NULL
2 rows in set (0.00 sec)

ERROR: 
No query specified

我們可以看到,有兩個分區。注:database()

那麼向RANGE分區表中插入數據結果回事怎麼樣的呢?


mysql> insert into t values (1),(2),(3);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> insert into t values (10),(12),(13);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from information_schema.PARTITIONS where table_schema=database() and table_name='t'\G;
*************************** 1. row ***************************
                TABLE_CATALOG: def
                 TABLE_SCHEMA: odp
                   TABLE_NAME: t
               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: 3
               AVG_ROW_LENGTH: 5461
                  DATA_LENGTH: 16384
              MAX_DATA_LENGTH: NULL
                 INDEX_LENGTH: 0
                    DATA_FREE: 0
                  CREATE_TIME: 2018-07-02 14:40:27
                  UPDATE_TIME: NULL
                   CHECK_TIME: NULL
                     CHECKSUM: NULL
            PARTITION_COMMENT: 
                    NODEGROUP: default
              TABLESPACE_NAME: NULL
*************************** 2. row ***************************
                TABLE_CATALOG: def
                 TABLE_SCHEMA: odp
                   TABLE_NAME: t
               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: 2018-07-02 14:40:27
                  UPDATE_TIME: NULL
                   CHECK_TIME: NULL
                     CHECKSUM: NULL
            PARTITION_COMMENT: 
                    NODEGROUP: default
              TABLESPACE_NAME: NULL
2 rows in set (0.00 sec)

ERROR: 
No query specified

我們可以看到插入每個分區表中分別是3條數據。so 當插入數據的值小於10就會寫入分區p0,插入數據大於等於10,小於20的數據插入了p1分區(分區範圍是左閉右合區間)

這個時候我們會發現一個BUG,當我們插入大於20的數據的時候,會怎麼樣呢?一起來測試一下

mysql> insert into t values (21),(22),(30);
ERROR 1526 (HY000): Table has no partition for value 21

沒錯!Mysql報錯,說是這個表沒有存放21的分區,這可怎麼辦呢?
沒錯!這個時候,我們可以添加一個maxvalue值得分區,詳細如下:

mysql> alter table t add partition (partition p2 values less than maxvalue);
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> insert into t values (21),(22),(30);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

我們可以看到,當我們添加一個maxvalue分區之後,在添加比20大的值得時候就不會報錯了。
來我們看看分區情況:

mysql> select * from information_schema.PARTITIONS where table_schema=database() and table_name='t'\G;
*************************** 1. row ***************************
                TABLE_CATALOG: def
                 TABLE_SCHEMA: odp
                   TABLE_NAME: t
               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: 6
               AVG_ROW_LENGTH: 2730
                  DATA_LENGTH: 16384
              MAX_DATA_LENGTH: NULL
                 INDEX_LENGTH: 0
                    DATA_FREE: 0
                  CREATE_TIME: 2018-07-02 15:28:28
                  UPDATE_TIME: NULL
                   CHECK_TIME: NULL
                     CHECKSUM: NULL
            PARTITION_COMMENT: 
                    NODEGROUP: default
              TABLESPACE_NAME: NULL
*************************** 2. row ***************************
                TABLE_CATALOG: def
                 TABLE_SCHEMA: odp
                   TABLE_NAME: t
               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: 2018-07-02 15:28:28
                  UPDATE_TIME: NULL
                   CHECK_TIME: NULL
                     CHECKSUM: NULL
            PARTITION_COMMENT: 
                    NODEGROUP: default
              TABLESPACE_NAME: NULL
*************************** 3. row ***************************
                TABLE_CATALOG: def
                 TABLE_SCHEMA: odp
                   TABLE_NAME: t
               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: 3
               AVG_ROW_LENGTH: 5461
                  DATA_LENGTH: 16384
              MAX_DATA_LENGTH: NULL
                 INDEX_LENGTH: 0
                    DATA_FREE: 0
                  CREATE_TIME: 2018-07-02 15:28:28
                  UPDATE_TIME: NULL
                   CHECK_TIME: NULL
                     CHECKSUM: NULL
            PARTITION_COMMENT: 
                    NODEGROUP: default
              TABLESPACE_NAME: NULL
3 rows in set (0.00 sec)

ERROR: 
No query specified

我看可以看到,我們成功的添加了一個值爲maxvalue的分區。

RANGE分主要用於日期列的分區,簡單實例:

-- 創建表
mysql> create table sales(
    -> money int unsigned not null,
    -> data datetime
    -> )engine=innodb
    -> partition by range (YEAR(data)) (
    ->   partition p2016 values less than (2016),
    ->   partition p2017 values less than (2017),
    ->   partition p2018 values less than (2018)
    -> );
Query OK, 0 rows affected (0.06 sec)

-- 插入數據

mysql> insert into sales values (100, '2015-08-09');
Query OK, 1 row affected (0.02 sec)

mysql> insert into sales values (100, '2016-08-09');
Query OK, 1 row affected (0.00 sec)

mysql> insert into sales values (100, '2017-08-09');
Query OK, 1 row affected (0.00 sec)

如果現在我們想刪除2015年的數據,我們就不用用:delete from sales where data>="2015-01-01" and data <= "2016-01-01"而是直接刪除2016分區即可:

mysql> alter table sales drop partition p2016;
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

另外還有一個好處,比喻我們想查詢2017年的所有數據,我們可以這樣操作:

mysql> explain partitions select * from sales where data>="2017-01-01" and "2017-12-31"\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: sales
   partitions: p2018
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 2
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

ERROR: 
No query specified

經過了explain partitions命令我們可以發現,Mysql只掃描了p2018這一個分區的數據,這樣在應對海量數據的時候會大幅提升查詢速度。但是我們需要注意的是,在寫where條件的時候,儘量不要跨區,比喻上面的2017-12-31要比2018-01-01的性能更優。

LIST分區

LIST分區跟RANGE分區非常相似,不過RANGE分區值是連續的,而LIST分區的值是離散的。

不多說,上SQL:

mysql> 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)
    -> );
Query OK, 0 rows affected (0.04 sec)

mysql> insert into t_list values (1,1),(1,2);
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

我們看看分區情況

mysql> select TABLE_SCHEMA,PARTITION_NAME,TABLE_NAME,PARTITION_DESCRIPTION,PARTITION_EXPRESSION,TABLE_ROWS from information_schema.PARTITIONS where table_schema=database() and table_name='t_list'\G;
*************************** 1. row ***************************
         TABLE_SCHEMA: odp
       PARTITION_NAME: p0
           TABLE_NAME: t_list
PARTITION_DESCRIPTION: 1,3,5,7,9
 PARTITION_EXPRESSION: b
           TABLE_ROWS: 1
*************************** 2. row ***************************
         TABLE_SCHEMA: odp
       PARTITION_NAME: p1
           TABLE_NAME: t_list
PARTITION_DESCRIPTION: 0,2,4,6,8
 PARTITION_EXPRESSION: b
           TABLE_ROWS: 1
2 rows in set (0.00 sec)

ERROR: 
No query specified

我們可以看到每個分區都插入了一條數據。
寫到這裏,難免有一個疑問,如果我們插入的數據在我們規定的範圍之外,這個時候,LIST分區會怎麼處理呢?
其實在這個一點MyISAM存儲引擎和INNODB存儲引擎的處理方式是不一樣的,MyISAM會將之前符合要求的數據插入,之後的數據則不會插入。Innodb存儲引擎將其視爲一個事務,因此沒有任何數據插入。
下面我們來演示一下:

-- 創建表
mysql> create table t_list_m(
    -> a int,
    -> b int
    -> )engine=MyISAM
    -> partition by list(b)(
    ->   partition p0 values in (1,3,5,7,9),
    ->   partition p1 values in (0,2,4,6,8)
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> create table t_list_i(
    -> 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)
    -> );
Query OK, 0 rows affected (0.02 sec)

-- 插入數據
mysql> insert into t_list_m values (1,2),(1,20);
ERROR 1526 (HY000): Table has no partition for value 20

mysql> insert into t_list_i values (1,2), (1,20);
ERROR 1526 (HY000): Table has no partition for value 20

-- 我們可以看到,都報錯,那我們來查看一下存入的內容
mysql> select * from t_list_m;
+------+------+
| a    | b    |
+------+------+
|    1 |    2 |
+------+------+
1 row in set (0.00 sec)

mysql> select * from t_list_i;
Empty set (0.00 sec)

這個結果也就印證了上面所說的結果!
因此我們在設置分區的時候,一定要考慮清楚使用哪種!

HASH分區

HASH分區的目的是將數據均勻的分佈到預先定義的各個分區中,保證各個分區的內容大體一致。在RANGE和LIST分區中必須給出指定列的列值或列值的集合,而HASH分區則是自動完成這些工作,用戶所要做的只是基於將要進行的哈希分區的列值指定一個列值或表達式,以及指定被分區的表將要被分割成的分區數量。

上SQL:

mysql> create table t_hash(
    ->   a int ,
    ->   b datetime
    -> )engine=INNODB
    -> partition by hash(year(b))
    -> partitions 4; -- 創建幾個分區(非負數,默認爲1Query OK, 0 rows affected (0.06 sec)

查看一下分區情況

mysql> select TABLE_SCHEMA,PARTITION_NAME,TABLE_NAME,PARTITION_DESCRIPTION,PARTITION_EXPRESSION,TABLE_ROWS from information_schema.PARTITIONS where table_schema=database() and table_name='t_hash'\G;
*************************** 1. row ***************************
         TABLE_SCHEMA: odp
       PARTITION_NAME: p0
           TABLE_NAME: t_hash
PARTITION_DESCRIPTION: NULL
 PARTITION_EXPRESSION: year(b)
           TABLE_ROWS: 0
*************************** 2. row ***************************
         TABLE_SCHEMA: odp
       PARTITION_NAME: p1
           TABLE_NAME: t_hash
PARTITION_DESCRIPTION: NULL
 PARTITION_EXPRESSION: year(b)
           TABLE_ROWS: 0
*************************** 3. row ***************************
         TABLE_SCHEMA: odp
       PARTITION_NAME: p2
           TABLE_NAME: t_hash
PARTITION_DESCRIPTION: NULL
 PARTITION_EXPRESSION: year(b)
           TABLE_ROWS: 0
*************************** 4. row ***************************
         TABLE_SCHEMA: odp
       PARTITION_NAME: p3
           TABLE_NAME: t_hash
PARTITION_DESCRIPTION: NULL
 PARTITION_EXPRESSION: year(b)
           TABLE_ROWS: 0
4 rows in set (0.00 sec)

ERROR: 
No query specified

那麼現在我有一個日期:2017-01-09應該被存入那個分區呢?
我們可以這樣計算,2017%4=1所以應該會被存入p1這個分區,我們來測試一下。

mysql> insert into t_hash values (1, "2017-01-09");
Query OK, 1 row affected (0.01 sec)

mysql> select TABLE_SCHEMA,PARTITION_NAME,TABLE_NAME,PARTITION_DESCRIPTION,PARTITION_EXPRESSION,TABLE_ROWS from information_schema.PARTITIONS where table_schema=database() and table_name='t_hash'\G;
*************************** 1. row ***************************
         TABLE_SCHEMA: odp
       PARTITION_NAME: p0
           TABLE_NAME: t_hash
PARTITION_DESCRIPTION: NULL
 PARTITION_EXPRESSION: year(b)
           TABLE_ROWS: 0
*************************** 2. row ***************************
         TABLE_SCHEMA: odp
       PARTITION_NAME: p1
           TABLE_NAME: t_hash
PARTITION_DESCRIPTION: NULL
 PARTITION_EXPRESSION: year(b)
           TABLE_ROWS: 1
*************************** 3. row ***************************
         TABLE_SCHEMA: odp
       PARTITION_NAME: p2
           TABLE_NAME: t_hash
PARTITION_DESCRIPTION: NULL
 PARTITION_EXPRESSION: year(b)
           TABLE_ROWS: 0
*************************** 4. row ***************************
         TABLE_SCHEMA: odp
       PARTITION_NAME: p3
           TABLE_NAME: t_hash
PARTITION_DESCRIPTION: NULL
 PARTITION_EXPRESSION: year(b)
           TABLE_ROWS: 0
4 rows in set (0.00 sec)

ERROR: 
No query specified

我們可以看到只有p1這個分區添加了一條數據。簡單的說明HASH是按照取餘的方式均勻的插入到表中。

KEY分區

KEY分區與HASH分區相似,不過HASH是通過用戶自定義的函數進行分區,KEY則是通過數據庫函數來分區的,對於MYSQL來說,NDB引擎是通過MD5來分區,其他則是通過哈希函數,這些函數是基於與PASSWORD()一樣的運算法則:

廢話不多說,上SQL:

mysql> create table t_key(
    ->   a int ,
    ->   b datetime
    -> )engine=INNODB
    -> partition by key(b)
    -> partitions 4;
Query OK, 0 rows affected (0.04 sec)

COLUMNS分區

前面介紹的RANGE、HASH、KEY和LIST這四個分區的條件都是:數據必須是整型,不是整型也要通過內置函數轉化成整型,比喻:YEAR(),TO_DAYS(),MONTH()等!從MYSQL5.5版本之後就可以使用COLUMNS分區,可視爲RANGE和LIST分區的一種進化。

COLUMNS支持的分區:

  1. 所有整型:INT、SMALLINT、TINYINT、BIGINT。FLOAT和DECIMAL則不予支持。
  2. 日期類型:DATE和DATETIME。其他日期類型不予支持。
  3. 字符串類型:CHAR、VARCHAR、BINARY和VARBIARY。BLOB和TEXT則不予支持。
    上SQL:

mysql> create table t_columns_range(
    -> a int,
    -> b datetime
    -> )engine=INNODB
    -> partition by RANGE COLUMNS(b)
    -> (
    -> partition p0 values less than ("2018-01-01"),
    -> partition p1 values less than ("2019-01-01")
    -> );

Query OK, 0 rows affected (0.03 sec)


mysql> create table t_columns_list(
    ->   first_name varchar (25),
    ->   last_name varchar (25),
    ->   city varchar (30)
    -> )engine=INNODB
    -> partition by LIST COLUMNS (city)(
    ->   partition p0 values in ("beijing"),
    ->   partition p1 values in ("shanghai"),
    ->   partition p2 values in ("shenzhen")
    -> );
Query OK, 0 rows affected (0.03 sec)

-- RANGE COLUMNS支持多列分區
mysql> create table t_columns_ranges(
    ->   a int,
    ->   b smallint ,
    ->   c char (3)
    -> )engine=INNODB
    -> partition by RANGE COLUMNS(a,b,c)
    -> (
    -> partition p0 values less than (5, 5, "man"),
    -> partition p1 values less than (10, 20, "woman")
    -> );

Query OK, 0 rows affected (0.03 sec

通過以上SQL,我們可以非常清楚的看出,之前的RANGE和LIST分區可以被RANGE COLUMNSLIST COLUMNS所代替。

子分區

子分區就是在分區的基礎上在分區,有時也稱這中分區爲複合分區。

創建一個複合分區:

mysql> create table t_sun(
    ->   a int,
    ->   b datetime
    -> )engine=INNODB
    -> partition by RANGE (YEAR(b))
    -> SUBPARTITION by HASH (TO_DAYS(b))
    -> SUBPARTITIONS 2(
    ->   PARTITION p0 VALUES LESS THAN (2017),
    ->   PARTITION p1 VALUES LESS THAN (2018),
    ->   PARTITION p2 VALUES LESS THAN (MAXVALUE)
    -> );
Query OK, 0 rows affected (0.08 sec)

查看一下生成的文件:


mysql> system ls -lh  /var/lib/mysql/odp/t_sun*
-rw-rw----  1 chenyang chenyang 8.4K Jul  3 18:04 /home/chenyang/.jumbo/var/lib/mysql/odp/t_sun.frm
-rw-rw----  1 chenyang chenyang   96 Jul  3 18:04 /home/chenyang/.jumbo/var/lib/mysql/odp/t_sun.par
-rw-rw----  1 chenyang chenyang  96K Jul  3 18:04 /home/chenyang/.jumbo/var/lib/mysql/odp/t_sun#P#p0#SP#p0sp0.ibd
-rw-rw----  1 chenyang chenyang  96K Jul  3 18:04 /home/chenyang/.jumbo/var/lib/mysql/odp/t_sun#P#p0#SP#p0sp1.ibd
-rw-rw----  1 chenyang chenyang  96K Jul  3 18:04 /home/chenyang/.jumbo/var/lib/mysql/odp/t_sun#P#p1#SP#p1sp0.ibd
-rw-rw----  1 chenyang chenyang  96K Jul  3 18:04 /home/chenyang/.jumbo/var/lib/mysql/odp/t_sun#P#p1#SP#p1sp1.ibd
-rw-rw----  1 chenyang chenyang  96K Jul  3 18:04 /home/chenyang/.jumbo/var/lib/mysql/odp/t_sun#P#p2#SP#p2sp0.ibd
-rw-rw----  1 chenyang chenyang  96K Jul  3 18:04 /home/chenyang/.jumbo/var/lib/mysql/odp/t_sun#P#p2#SP#p2sp1.ibd
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章