mysql分區表操作詳細

 

一、       mysql分區簡介

數據庫分區

數據庫分區是一種物理數據庫設計技術。雖然分區技術可以實現很多效果,但其主要目的是爲了在特定的SQL操作中減少數據讀寫的總量以縮減sql語句的響應時間,同時對於應用來說分區完全是透明的。

MYSQL的分區主要有兩種形式:水平分區和垂直分區

 

水平分區(HorizontalPartitioning)

這種形式的分區是對根據表的行進行分區,通過這樣的方式不同分組裏面的物理列分割的數據集得以組合,從而進行個體分割(單分區)或集體分割(1個或多個分區)。
所有在表中定義的列在每個數據集中都能找到,所以表的特性依然得以保持。水平分區一定要通過某個屬性列來分割。常見的比如年份,日期等。

 

垂直分區(VerticalPartitioning)

這種分區方式一般來說是通過對錶的垂直劃分來減少目標表的寬度,使某些特定的列被劃分到特定的分區,每個分區都包含了其中的列所對應所有行。
可以用  showvariables like '%partition%';

命令查詢當前的mysql數據庫版本是否支持分區。

分區的作用:數據庫性能的提升和簡化數據管理

在掃描操作中,mysql優化器只掃描保護數據的那個分區以減少掃描範圍獲得性能的提高。

分區技術使得數據管理變得簡單,刪除某個分區不會對另外的分區造成影響,分區有系統直接管理不用手工干預。

mysql從5.1版本開始支持分區。每個分區的名稱是不區分大小寫。同個表中的分區表名稱要唯一。

二、       mysql分區類型

根據所使用的不同分區規則可以分成幾大分區類型。

RANGE 分區:

基於屬於一個給定連續區間的列值,把多行分配給分區。

LIST 分區:

類似於按RANGE分區,區別在於LIST分區是基於列值匹配一個離散值集合中的某個值來進行選擇。

HASH分區:

基於用戶定義的表達式的返回值來進行選擇的分區,該表達式使用將要插入到表中的這些行的列值進行計算。這個函數可以包含MySQL中有效的、產生非負整數值的任何表達式。

KEY
分區:類似於按HASH分區,區別在於KEY分區只支持計算一列或多列,且MySQL服務器提供其自身的哈希函數。必須有一列或多列包含整數值。

複合分區:

基於RANGE/LIST 類型的分區表中每個分區的再次分割。子分區可以是 HASH/KEY 等類型。

 

三、       mysql分區表常用操作示例

以部門員工表爲例子:

1)       創建range分區

 

create table emp

(empno varchar(20not null ,

empname varchar(20),

deptno int,

birthdate date,

salary int

)

partition by range(salary)

(

partition p1 values less than (1000),

partition p2 values less than (2000),

partition p3 values less than maxvalue

);

以員工工資爲依據做範圍分區。

 

create table emp

(empno varchar(20not null ,

empname varchar(20),

deptno int,

birthdate date not null,

salary int

)

partition by range(year(birthdate))

(

partition p1 values less than (1980),

partition p2 values less than (1990),

partition p3 values less than maxvalue

);

year(birthdate)表達式(計算員工的出生日期)作爲範圍分區依據。這裏最值得注意的是表達式必須有返回值。

 

2)       創建list分區

 

create table emp

(empno  varchar(20not null ,

empname varchar(20),

deptno  int,

birthdate date not null,

salary int

)

partition by list(deptno)

(

partition p1 values in  (10),

partition p2 values in  (20),

partition p3 values  in  (30)

);

以部門作爲分區依據,每個部門做一分區。

 

3)       創建hash分區

HASH分區主要用來確保數據在預先確定數目的分區中平均分佈。在RANGE和LIST分區中,必須明確指定一個給定的列值或列值集合應該保存在哪個分區中;而在HASH分區中,MySQL 自動完成這些工作,你所要做的只是基於將要被哈希的列值指定一個列值或表達式,以及指定被分區的表將要被分割成的分區數量。

create table emp

(empno varchar(20not null ,

empname varchar(20),

deptno int,

birthdate date not null,

salary int

)

partition by hash(year(birthdate))

partitions 4;

4)       創建key分區

按照KEY進行分區類似於按照HASH分區,除了HASH分區使用的用戶定義的表達式,而KEY分區的哈希函數是由MySQL 服務器提供,服務器使用其自己內部的哈希函數,這些函數是基於與PASSWORD()一樣的運算法則。“CREATE TABLE ...PARTITION BY KEY”的語法規則類似於創建一個通過HASH分區的表的規則。它們唯一的區別在於使用的關鍵字是KEY而不是HASH,並且KEY分區只採用一個或多個列名的一個列表。

create table emp

(empno varchar(20not null ,

empname varchar(20),

deptno int,

birthdate date not null,

salary int

)

partition by key(birthdate)

partitions 4;

 

 

5)       創建複合分區

 

range - hash(範圍哈希)複合分區

 

create table emp

(empno varchar(20not null ,

empname varchar(20),

deptno int,

birthdate date not null,

salary int

)

partition by range(salary)

subpartition by hash(year(birthdate))

subpartitions 3

(

partition p1 values less than (2000),

partition p2 values less than maxvalue

);

range- key複合分區

 

create table emp

(empno varchar(20not null ,

empname varchar(20),

deptno int,

birthdate date not null,

salary int

)

partition by range(salary)

subpartition by key(birthdate)

subpartitions 3

(

partition p1 values less than (2000),

partition p2 values less than maxvalue

);

list - hash複合分區

CREATE TABLE emp (

empno varchar(20NOT NULL,

empname varchar(20) ,

deptno int,

birthdate date NOT NULL,

salary int

)

PARTITION BY list (deptno)

subpartition by hash(year(birthdate))

subpartitions 3

(

PARTITION p1 VALUES in  (10),

PARTITION p2 VALUES in  (20)

)

;

list - key 複合分區

 

CREATE TABLE empk (

empno varchar(20NOT NULL,

empname varchar(20) ,

deptno int,

birthdate date NOT NULL,

salary int

)

PARTITION BY list (deptno)

subpartition by key(birthdate)

subpartitions 3

(

PARTITION p1 VALUES in  (10),

PARTITION p2 VALUES in  (20)

)

;

6)       分區表的管理操作

刪除分區:

alter table emp drop partition p1;

不可以刪除hash或者key分區。

一次性刪除多個分區,alter table emp drop partition p1,p2;

 

增加分區:

alter table emp add partition (partition p3 values less than (4000));

alter table empl add partition (partition p3 values in (40));

 

分解分區:

Reorganizepartition關鍵字可以對錶的部分分區或全部分區進行修改,並且不會丟失數據。分解前後分區的整體範圍應該一致。

alter table te

reorganize partition p1 into

(

partition p1 values less than (100),

partition p3 values less than (1000)

); ----不會丟失數據

 

合併分區:

Merge分區:把2個分區合併爲一個。
alter table te

reorganize partition p1,p3 into

(partition p1 values less than (1000));

----不會丟失數據

 

重新定義hash分區表:

Alter table emp partition by hash(salary)partitions 7;

----不會丟失數據

重新定義range分區表:

Alter table emp partitionbyrange(salary)

(

partition p1 values less than (2000),

partition p2 values less than (4000)

); ----不會丟失數據

 

刪除表的所有分區:

 

Alter table emp removepartitioning;--不會丟失數據

 

重建分區:

這和先刪除保存在分區中的所有記錄,然後重新插入它們,具有同樣的效果。它可用於整理分區碎片。

ALTER TABLE emp rebuild partitionp1,p2;

 

優化分區:

如果從分區中刪除了大量的行,或者對一個帶有可變長度的行(也就是說,有VARCHAR,BLOB,或TEXT類型的列)作了許多修改,可以使用“ALTER TABLE ... OPTIMIZE PARTITION”來收回沒有使用的空間,並整理分區數據文件的碎片。

ALTER TABLE emp optimize partition p1,p2;

 

分析分區:

讀取並保存分區的鍵分佈。

ALTER TABLE emp analyze partition p1,p2;

 

修補分區:

修補被破壞的分區。

ALTER TABLE emp repairpartition p1,p2;

 

檢查分區:

可以使用幾乎與對非分區表使用CHECK TABLE 相同的方式檢查分區。

ALTER TABLE emp CHECK partition p1,p2;

這個命令可以告訴你表emp的分區p1,p2中的數據或索引是否已經被破壞。如果發生了這種情況,使用“ALTER TABLE ... REPAIR PARTITION”來修補該分區。

 

 

【mysql分區表的侷限性】

1.      在5.1版本中分區表對唯一約束有明確的規定,每一個唯一約束必須包含在分區表的分區鍵(也包括主鍵約束)。

 

CREATE TABLE emptt (

empno varchar(20NOT NULL  ,

empname varchar(20),

deptno int,

birthdate date NOT NULL,

salary int ,

primary key (empno)

)

PARTITION BY range (salary)

(

PARTITION p1 VALUES less than (100),

PARTITION p2 VALUES less than (200)

);

這樣的語句會報錯。MySQL Database Error: A PRIMARY KEY must include allcolumns in the table's partitioning function;

CREATE TABLE emptt (

empno varchar(20NOT NULL  ,

empname varchar(20) ,

deptno int(11),

birthdate date NOT NULL,

salary int(11) ,

primary key (empno,salary)

)

PARTITION BY range (salary)

(

PARTITION p1 VALUES less than (100),

PARTITION p2 VALUES less than (200)

);

在主鍵中加入salary列就正常。

 

2.      MySQL分區處理NULL值的方式

如果分區鍵所在列沒有notnull約束。

如果是range分區表,那麼null行將被保存在範圍最小的分區。

如果是list分區表,那麼null行將被保存到list爲0的分區。

在按HASH和KEY分區的情況下,任何產生NULL值的表達式mysql都視同它的返回值爲0。

爲了避免這種情況的產生,建議分區鍵設置成NOT NULL。

 

3.      分區鍵必須是INT類型,或者通過表達式返回INT類型,可以爲NULL。唯一的例外是當分

區類型爲KEY分區的時候,可以使用其他類型的列作爲分區鍵( BLOB or TEXT 列除外)。

 

4.      對分區表的分區鍵創建索引,那麼這個索引也將被分區,分區鍵沒有全局索引一說。

5.      只有RANG和LIST分區能進行子分區,HASH和KEY分區不能進行子分區。

6.      臨時表不能被分區。

 

四、       獲取mysql分區表信息的幾種方法

1.     show create table 表名
可以查看創建分區表的create語句 
 

2.     show table status 
可以查看錶是不是分區表 
 

3.     查看information_schema.partitions表 
select 
  partition_name part,  
  partition_expression expr,  
  partition_description descr,  
  table_rows  
from information_schema.partitions  where 
  table_schema = schema()  
  and table_name='test';  
可以查看錶具有哪幾個分區、分區的方法、分區中數據的記錄數等信息

4.     explain partitions select語句
通過此語句來顯示掃描哪些分區,及他們是如何使用的.

 

五、       分區表性能比較

1.     創建兩張表: part_tab(分區表),no_part_tab(普通表)

CREATE TABLEpart_tab

( c1 int defaultNULL, c2 varchar2(30) default NULL, c3 date not null)

PARTITION BYRANGE(year(c3))

(PARTITION p0VALUES LESS THAN (1995),

PARTITION p1 VALUESLESS THAN (1996) ,

PARTITION p2 VALUESLESS THAN (1997) ,

PARTITION p3 VALUESLESS THAN (1998) ,

 PARTITION p4 VALUES LESS THAN (1999) ,

PARTITION p5 VALUESLESS THAN (2000) ,

PARTITION p6 VALUESLESS THAN (2001) ,

PARTITION p7 VALUESLESS THAN (2002) ,

PARTITION p8 VALUESLESS THAN (2003) ,

PARTITION p9 VALUESLESS THAN (2004) ,

PARTITION p10VALUES LESS THAN (2010),

PARTITION p11VALUES LESS THAN (MAXVALUE) );

CREATE TABLE no_part_tab

( c1 int defaultNULL, c2 varchar2(30) default NULL, c3 date not null);

 

2.     用存儲過程插入800萬條數據

CREATE PROCEDUREload_part_tab()

    begin

    declare v int default 0;

    while v < 8000000

    do

        insert into part_tab

        values (v,'testingpartitions',adddate('1995-01-01',(rand(v)*36520)mod 3652));

         set v = v + 1;

    end while;

end;

insert into no_part_tab  select * frompart_tab;

3.     測試sql性能

查詢分區表:

selectcount(*) from part_tab where c3 > date '1995-01-01'and c3 < date '1995-12-31';

+----------+
| count(*) |
+----------+
|   795181 |
+----------+
1 row in set (2.62 sec)

查詢普通表:

selectcount(*) from part_tab where c3 > date '1995-01-01'and c3 < date '1995-12-31';

+----------+
| count(*) |
+----------+
|   795181 |
+----------+
1 row in set (7.33 sec)

分區表的執行時間比普通表少70%。

 

4.     通過explain語句來分析執行情況

mysql>explain select count(*) from part_tab where c3 > date '1995-01-01'and c3 < date '1995-12-31';

+----+-------------+----------+------+---------------+------+---------+------+---------+-------------+

| id |select_type | table    | type |possible_keys | key  | key_len | ref  | rows   | Extra       |

+----+-------------+----------+------+---------------+------+---------+------+---------+-------------+

|  1 | SIMPLE      | part_tab | ALL  | NULL          | NULL | NULL    | NULL | 7980796 | Using where |

+----+-------------+----------+------+---------------+------+---------+------+---------+-------------+

1 rowin set

 

mysql>explain select count(*) from no_part_tab where c3 > date '1995-01-01'and c3 < date '1995-12-31';

+----+-------------+-------------+------+---------------+------+---------+------+---------+-------------+

| id |select_type | table       | type |possible_keys | key  | key_len | ref  | rows   | Extra       |

+----+-------------+-------------+------+---------------+------+---------+------+---------+-------------+

|  1 | SIMPLE      | no_part_tab | ALL  | NULL          | NULL | NULL    | NULL | 8000206 | Using where |

+----+-------------+-------------+------+---------------+------+---------+------+---------+-------------+

1 rowin set

mysql >

分區表執行掃描了7980796行,而普通表則掃描了8000206行。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章