1. 程式人生 > >MySQL分區總結

MySQL分區總結

explain 測試 myisam sql 服務器 list分區 let category 基於 優點

前言:分區是指根據一定的規則,數據庫把一個表分解成多個更小的,更容易管理的部分。分區對應用來說是完全透明的,不影響應用的業務邏輯。

MySQL分區的優點:

  1、和單個磁盤或者文件系統分區相比,可以存儲更多數據;

  2、優化查詢。在Where字句中包含分區條件時,可以只掃描必要的一個或多個分區來提高查詢效率;同時在涉及 SUM() 和 COUNT() 等聚合函數的查詢時,可以容易地在每個分區上並行處理,最終只需要匯總所有分區得到的結果。

  3、對於已經過期或者不需要保存的數據,可以通過刪除與這些數據有關的分區來快速刪除數據。

  4、跨多個磁盤來分散數據查詢,以獲得更大的查詢吞吐量。

一:概述

  MySQL 支持使用大部分存儲引擎(如:MyISAM、InnoDB、Memory等)創建分區表,不支持使用MERGE和CSV。 MySQL分區類型主要包括:range分區、list分區、hash分區、key分區;無論是那種MySQL分區類型,要麽分區表上沒有主鍵/唯一鍵,要麽分區表的主鍵/唯一鍵都必須包含分區鍵,也就是說不能使用主鍵/唯一鍵字段之外的其他字段分區。如:

mysql> create table emp(
    ->     id int not null,
    ->     ename varchar(30),
    ->     hired date not null default ‘1970-01-01‘,
    ->     separated date not null default ‘9999-12-31‘,
    ->     job varchar(30) not null,
    ->     store_id int not null,
    ->     primary key(id)
    -> )
    -> partition by range (store_id) (
    ->     partition p0 values less than(10),
    ->     partition p1 values less than(20),
    ->     partition p2 values less than(30)
    -> );
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table‘s partitioning function

  去掉主鍵約束後,創建表會成功:

mysql> create table emp(
    -> id int not null,
    -> ename varchar(30),
    -> hired date not null default ‘1970-01-01‘,
    -> separated date not null default ‘9999-12-31‘,
    -> job varchar(30) not null,
    -> store_id int not null
    -> )
    -> partition by range (store_id) (
    -> partition p0 values less than(10),
    -> partition p1 values less than(20),
    -> partition p2 values less than(30)
    -> );
Query OK, 0 rows affected (0.02 sec)

  分區的名字遵循MySQL標識符的原則。分區的名字不區分大小寫,如果分區名分別為 mypart 和 MyPart 將會被MySQL認為是同一個分區而報錯。

二:RANGE分區

  按照range分區的表是利用取值範圍將數據分區,區間要連續並且不能互相重疊,使用 values less than 操作符進行分區定義。

mysql> create table emp(
    -> id int not null,
    -> ename varchar(30),
    -> hired date not null default ‘1970-01-01‘,
    -> separated date not null default ‘9999-12-31‘,
    -> job varchar(30) not null,
    -> store_id int not null
    -> )
    -> partition by range (store_id) (
    -> partition p0 values less than(10),
    -> partition p1 values less than(20),
    -> partition p2 values less than(30)
    -> );
Query OK, 0 rows affected (0.02 sec)

  如果增加商店ID大於等於30的行,超出分區範圍,會出現錯誤。

mysql> insert into emp(id,ename,hired,job,store_id) values (‘7934‘, ‘MILLER‘, ‘1982-01-23‘, ‘CLERK‘, 50);
ERROR 1526 (HY000): Table has no partition for value 50

  可以使用 values less than maxvalue 設置分區,超出明確指定的分區值時,數據會存儲在該分區,如:

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

mysql> insert into emp(id,ename,hired,job,store_id) values (‘7934‘, ‘MILLER‘, ‘1982-01-23‘, ‘CLERK‘, 50);
Query OK, 1 row affected (0.05 sec)

  MySQL支持在 values less than 字句中使用表達式 partition by range (year(separated)),可自行測試。類似的函數有 to_days()、to_seconds();5.5版本後可直接使用日期字段作為分區鍵。

Range分區特別使用的兩種情況:

  1、當需要刪除過期的數據時,只需要簡單的 ALTER TABLE emp DROP PARTITION p0 來刪除p0分區中的數據,對於具有上百萬條記錄的表來說,刪除分區要比運行一個 DELETE 語句有效得多。

  2、經常運行包含分區間的查詢,MySQL 可以很快地確定只有一個或者某些分區需要掃描,因為其他分區不可能包含有該 WHERE 字句的任何記錄。

三:List 分區

  List 分區是建立離散的值列表告訴數據庫特定的值屬於哪個分區,List 分區在很多方面類似於 Range 分區,區別在於 List 分區是從屬於一個枚舉列表的值得集合,Range 分區從屬於一個連續區間值得集合。

mysql> create table expenses(
    -> expense_date date not null,
    -> category int,
    -> amount decimal (10,3)
    -> )partition by list(category) (
    -> partition p0 values in (3, 5),
    -> partition p1 values in (1, 10),
    -> partition p2 values in (4, 9),
    -> partition p3 values in (2),
    -> partition p4 values in (6)
    -> );
Query OK, 0 rows affected (0.05 sec)

  如果插入的列值不包含分區值得列表中,insert 操作會失敗報錯。註意:List 分區不存在類似 values less than maxvalue 這樣包含其他值在內的定義方式。將要匹配的任何值都必須在值列表中。

四:Hash 分區

  Hash 分區主要用來分散熱點讀,確保數據在預先確定個數的分區中盡可能平均分布。MySQL 支持兩種 Hash 分區:常規 Hash 分區、線性 Hash 分區(Linear Hash 分區)。常規 Hash 分區使用的是取模算法,線性 Hash 分區使用的是一個線性的2的冪的運算法則。

1、常規 Hash 分區

  使用 PARTITION BY HASH(expr) PARTITIONS num 字句對分區類型、分區鍵和分區個數進行定義,其中 expr 是某列值或一個基於某列值返回的表達式。num 是一個非負整數,表示分區數量,默認為1。

mysql> create table emp_hash(
    -> id int not null,
    -> ename varchar(30),
    -> hired date not null default ‘1970-01-01‘,
    -> separated date not null default ‘9999-12-31‘,
    -> job varchar(30) not null,
    -> store_id int not null
    -> )
    -> partition by hash (store_id) partitions 4;
Query OK, 0 rows affected (0.03 sec)

  假設將要保存記錄的分區編號為N, 那麽 N=MOD(expr, num) 如,emp_hash表中有4個分區,插入一個 store_id列值為234的記錄到表中:

mysql> insert into emp_hash values (1, ‘Tom‘, ‘2010-10-10‘, ‘9999-12-31‘, ‘Clerk‘, 234);
Query OK, 1 row affected (0.01 sec)

  MOD(234, 4)=2 保存這條記錄的分區應該是p2;從p0 開始,模為 0 時保存到 p0 依次類推。

mysql> explain partitions select * from emp_hash where store_id =234\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: emp_hash
   partitions: p2
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 2
        Extra: Using where
1 row in set (0.05 sec)

  不推薦使用涉及多列的哈希表達式,復雜的表達式可能會引起性能問題。常規 Hash 在分區管理上需要的代價高,不適合需要靈活變動分區的需求。

2、線性 Hash 分區(Linear Hash)

  線性 Hash 分區和常規 Hash 分區 在語法上的唯一區別是在 partition by 字句中添加關鍵字 “Linear”,如:

mysql> create table emp_linear(
    -> id int not null,
    -> ename varchar(30),
    -> hired date not null default ‘1970-01-01‘,
    -> separated date not null default ‘9999-12-31‘,
    -> job varchar(30) not null,
    -> store_id int not null
    -> )
    -> partition by linear hash (store_id) partitions 4;
Query OK, 0 rows affected (0.03 sec)

  線性Hash分區的優點是:在分區維護(增加、刪除、合並、拆分分區時),MySQL能夠處理得更加迅速;缺點是:對比常規的Hash分區(取模)的時候,線性Hash各個分區之間數據的分布不太均衡。

五:Key 分區

  Key 分區類似於 Hash 分區,不過 Key 分區不允許使用用戶自定義的表達式,需要使用 MySQL 服務器提供的 Hash 函數;同時 Hash 分區只支持整數分區,而 Key 分區支持使用 Blob 或 Text 類型外其他類型的列作為分區鍵

mysql> create table emp_key(
    -> id int not null,
    -> ename varchar(30),
    -> hired date not null default ‘1970-01-01‘,
    -> separated date not null default ‘9999-12-31‘,
    -> job varchar(30) not null,
    -> store_id int not null
    -> )
    -> partition by key (job) partitions 4;
Query OK, 0 rows affected (0.05 sec)

  創建 Key 分區表的時候,可以不指定分區鍵,默認會首先選擇使用主鍵作為分區鍵

mysql> create table emp_key1(
    -> id int not null,
    -> ename varchar(30),
    -> hired date not null default ‘1970-01-01‘,
    -> separated date not null default ‘9999-12-31‘,
    -> job varchar(30) not null,
    -> store_id int not null
    -> )
    -> partition by key () partitions 4;
Query OK, 0 rows affected (0.03 sec)

  在沒有主鍵的情況,會選擇非空唯一鍵作為分區鍵,分區鍵的唯一鍵必須是非空的,如果不是非空會報錯:

mysql> create table emp_key2(
    -> id int not null,
    -> ename varchar(30),
    -> hired date not null default ‘1970-01-01‘,
    -> separated date not null default ‘9999-12-31‘,
    -> job varchar(30) not null,
    -> store_id int not null,
	-> unique key(id)
    -> )
    -> partition by key () partitions 4;
Query OK, 0 rows affected (0.03 sec)

  和 Hash 分區類似,在 Key 分區中使用關鍵字 Linear 具有同樣的作用,Linear Key 分區時,分區的編號是通過2的冪算法得到的,不是通過取模得到的。

附:MySQL 分區的 null 值處理

  1、MySQL 分區不禁止在分區鍵值上使用 null

  2、Range 分區中,null 值會被當做最小值來處理

  3、List 分區中,null 值必須出現在枚舉列表中,否則不被接受

  4、Hash/Key 分區中,null 值會被當做零值來處理

  5、為了避免在處理 null 值時出現誤判,推薦通過設置字段非空和默認值來繞開 MySQL 對 null 值的默認處理

MySQL分區總結