MySQL表的四種分區類型&創建,增加,刪除mysql表分區

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">一、什麼是表分區</span>

通俗地講表分區是將一大表,根據條件分割成若干個小表。mysql5.1開始支持數據表分區了。 如:某用戶表的記錄超過了600萬條,那麼就可以根據入庫日期將表分區,也可以根據所在地將表分區。當然也可根據其他的條件分區。

二、爲什麼要對錶進行分區

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

分區的一些優點包括:

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

三、分區類型

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

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

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

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

RANGE分區

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

這些區間要連續且不能相互重疊,使用VALUES LESS THAN操作符來進行定義。以下是實例。

Sql代碼:
CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT NOT NULL,
    store_id INT NOT NULL
)

partition BY RANGE (store_id) (
    partition p0 VALUES LESS THAN (6),
    partition p1 VALUES LESS THAN (11),
    partition p2 VALUES LESS THAN (16),
    partition p3 VALUES LESS THAN (21)
);

按照這種分區方案,在商店1到5工作的僱員相對應的所有行被保存在分區P0中,商店6到10的僱員保存在P1中,依次類推。注意,每個分區都是按順序進行定義,從最低到最高。這是PARTITION BY RANGE 語法的要求;在這點上,它類似於C或Java中的“switch … case”語句。對於包含數據(72, ‘Michael’, ‘Widenius’, ’1998-06-25′, NULL, 13)的一個新行,可以很容易地確定它將插入到p2分區中,但是如果增加了一個編號爲第21的商店,將會發生什麼呢?在這種方案下,由於沒有規則把store_id大於20的商店包含在內,服務器將不知道把該行保存在何處,將會導致錯誤。 要避免這種錯誤,可以通過在CREATE TABLE語句中使用一個“catchall” VALUES LESS THAN子句,該子句提供給所有大於明確指定的最高值的值:

Sql代碼:
CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT NOT NULL,
    store_id INT NOT NULL
)

PARTITION BY RANGE (store_id) (
    PARTITION p0 VALUES LESS THAN (6),
    PARTITION p1 VALUES LESS THAN (11),
    PARTITION p2 VALUES LESS THAN (16),
    PARTITION p3 VALUES LESS THAN MAXVALUE
);

MAXVALUE 表示最大的可能的整數值。現在,store_id 列值大於或等於16(定義了的最高值)的所有行都將保存在分區p3中。在將來的某個時候,當商店數已經增長到25, 30, 或更多 ,可以使用ALTER TABLE語句爲商店21-25, 26-30,等等增加新的分區。在幾乎一樣的結構中,你還可以基於僱員的工作代碼來分割表,也就是說,基於job_code 列值的連續區間。例如——假定2位數字的工作代碼用來表示普通(店內的)工人,三個數字代碼表示辦公室和支持人員,四個數字代碼表示管理層,你可以使用下面的語句創建該分區表:

Sql代碼:
CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT NOT NULL,
    store_id INT NOT NULL
)

PARTITION BY RANGE (job_code) (
    PARTITION p0 VALUES LESS THAN (100),
    PARTITION p1 VALUES LESS THAN (1000),
    PARTITION p2 VALUES LESS THAN (10000)
);

在這個例子中, 店內工人相關的所有行將保存在分區p0中,辦公室和支持人員相關的所有行保存在分區p1中,管理層相關的所有行保存在分區p2中。在VALUES LESS THAN 子句中使用一個表達式也是可能的。這裏最值得注意的限制是MySQL 必須能夠計算表達式的返回值作爲LESS THAN (<)比較的一部分;因此,表達式的值不能爲NULL 。由於這個原因,僱員表的hired, separated, job_code,和store_id列已經被定義爲非空(NOT NULL)。除了可以根據商店編號分割表數據外,你還可以使用一個基於兩個DATE (日期)中的一個的表達式來分割表數據。例如,假定你想基於每個僱員離開公司的年份來分割表,也就是說,YEAR(separated)的值。實現這種分區模式的CREATE TABLE 語句的一個例子如下所示:

Sql代碼:
CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)

PARTITION BY RANGE (YEAR(separated)) (
    PARTITION p0 VALUES LESS THAN (1991),
    PARTITION p1 VALUES LESS THAN (1996),
    PARTITION p2 VALUES LESS THAN (2001),
    PARTITION p3 VALUES LESS THAN MAXVALUE
);

在這個方案中,在1991年前僱傭的所有僱員的記錄保存在分區p0中,1991年到1995年期間僱傭的所有僱員的記錄保存在分區p1中, 1996年到2000年期間僱傭的所有僱員的記錄保存在分區p2中,2000年後僱傭的所有工人的信息保存在p3中。

RANGE分區在如下場合特別有用:1)、當需要刪除一個分區上的“舊的”數據時,只刪除分區即可。如果你使用上面最近的那個例子給出的分區方案,你只需簡單地使用”ALTER TABLE employees DROP PARTITION p0;”來刪除所有在1991年前就已經停止工作的僱員相對應的所有行。對於有大量行的表,這比運行一個如”DELETE FROM employees WHERE YEAR (separated) <= 1990;”這樣的一個DELETE查詢要有效得多。 2)、想要使用一個包含有日期或時間值,或包含有從一些其他級數開始增長的值的列。3)、經常運行直接依賴於用於分割表的列的查詢。例如,當執行一個如”SELECT COUNT(*) FROM employees WHERE YEAR(separated) = 2000 GROUP BY store_id;”這樣的查詢時,MySQL可以很迅速地確定只有分區p2需要掃描,這是因爲餘下的分區不可能包含有符合該WHERE子句的任何記錄。

註釋:這種優化還沒有在MySQL 5.1源程序中啓用,但是,有關工作正在進行中。

LIST分區

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

LIST分區通過使用“PARTITION BY LIST(expr)”來實現,其中“expr”是某列值或一個基於某個列值、並返回一個整數值的表達式,然後通過“VALUES IN (value_list)”的方式來定義每個分區,其中“value_list”是一個通過逗號分隔的整數列表。 註釋:在MySQL 5.1中,當使用LIST分區時,有可能只能匹配整數列表。

Sql代碼:
CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
);

假定有20個音像店,分佈在4個有經銷權的地區,如下表所示:

====================

地區      商店ID 號

北區      3, 5, 6, 9, 17

東區      1, 2, 10, 11, 19, 20

西區      4, 12, 13, 14, 18

中心區   7, 8, 15, 16

====================

要按照屬於同一個地區商店的行保存在同一個分區中的方式來分割表,可以使用下面的“CREATE TABLE”語句:

Sql代碼:
CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)

PARTITION BY LIST(store_id)
    PARTITION pNorth VALUES IN (3,5,6,9,17),
    PARTITION pEast VALUES IN (1,2,10,11,19,20),
    PARTITION pWest VALUES IN (4,12,13,14,18),
    PARTITION pCentral VALUES IN (7,8,15,16)
);

這使得在表中增加或刪除指定地區的僱員記錄變得容易起來。例如,假定西區的所有音像店都賣給了其他公司。那麼與在西區音像店工作僱員相關的所有記錄(行)可以使用查詢“ALTER TABLE employees DROP PARTITION pWest;”來進行刪除,它與具有同樣作用的DELETE(刪除)查詢“DELETE query DELETE FROM employees WHERE store_id IN (4,12,13,14,18);”比起來,要有效得多。【要點】:如果試圖插入列值(或分區表達式的返回值)不在分區值列表中的一行時,那麼“INSERT”查詢將失敗並報錯。例如,假定LIST分區的採用上面的方案,下面的查詢將失敗:

Sql代碼:
INSERT INTO employees VALUES(224, 'Linus', 'Torvalds', '2002-05-01', '2004-10-12', 42, 21);
這是因爲“store_id”列值21不能在用於定義分區pNorth, pEast, pWest,或pCentral的值列表中找到。要重點注意的是,LIST分區沒有類似如“VALUES LESS THAN MAXVALUE”這樣的包含其他值在內的定義。將要匹配的任何值都必須在值列表中找到。

LIST分區除了能和RANGE分區結合起來生成一個複合的子分區,與HASH和KEY分區結合起來生成複合的子分區也是可能的。

HASH分區

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

要使用HASH分區來分割一個表,要在CREATE TABLE 語句上添加一個“PARTITION BY HASH (expr)”子句,其中“expr”是一個返回一個整數的表達式。它可以僅僅是字段類型爲MySQL整型的一列的名字。此外,你很可能需要在後面再添加一個“PARTITIONS num”子句,其中num是一個非負的整數,它表示表將要被分割成分區的數量。

Sql代碼:
CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY HASH(store_id)
PARTITIONS 4;

如果沒有包括一個PARTITIONS子句,那麼分區的數量將默認爲1。例外:對於NDB Cluster(簇)表,默認的分區數量將與簇數據節點的數量相同,這種修正可能是考慮任何MAX_ROWS設置,以便確保所有的行都能合適地插入到分區中。

LINER HASH

MySQL還支持線性哈希功能,它與常規哈希的區別在於,線性哈希功能使用的一個線性的2的冪(powers-of-two)運算法則,而常規哈希使用的是求哈希函數值的模數。線性哈希分區和常規哈希分區在語法上的唯一區別在於,在“PARTITION BY”子句中添加“LINEAR”關鍵字。

Sql代碼:
CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY LINEAR HASH(YEAR(hired))
PARTITIONS 4;

假設一個表達式expr,當使用線性哈希功能時,記錄將要保存到的分區是num 個分區中的分區N,其中N是根據下面的算法得到: 1. 找到下一個大於num.的、2的冪,我們把這個值稱爲V ,它可以通過下面的公式得到: 2. V = POWER(2, CEILING(LOG(2, num))) (例如,假定num是13。那麼LOG(2,13)就是3.7004397181411。 CEILING(3.7004397181411)就是4,則V = POWER(2,4), 即等於16)。 3. 設置 N = F(column_list) & (V – 1). 4.    當 N >= num: ·  設置 V = CEIL(V / 2) ·  設置 N = N & (V – 1) 例如,假設表t1,使用線性哈希分區且有4個分區,是通過下面的語句創建的: CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE) PARTITION BY LINEAR HASH( YEAR(col3) ) PARTITIONS 6; 現在假設要插入兩行記錄到表t1中,其中一條記錄col3列值爲’2003-04-14′,另一條記錄col3列值爲’1998-10-19′。第一條記錄將要保存到的分區確定如下: V = POWER(2, CEILING(LOG(2,7))) = 8 N = YEAR(’2003-04-14′) & (8 – 1)    = 2003 & 7    = 3 (3 >= 6 爲假(FALSE): 記錄將被保存到#3號分區中) 第二條記錄將要保存到的分區序號計算如下: V = 8 N = YEAR(’1998-10-19′) & (8-1)   = 1998 & 7   = 6 (6 >= 4 爲真(TRUE): 還需要附加的步驟) N = 6 & CEILING(5 / 2)   = 6 & 3   = 2   (2 >= 4 爲假(FALSE): 記錄將被保存到#2分區中) 按照線性哈希分區的優點在於增加、刪除、合併和拆分分區將變得更加快捷,有利於處理含有極其大量(1000吉)數據的表。它的缺點在於,與使用常規HASH分區得到的數據分佈相比,各個分區間數據的分佈不大可能均衡。

KSY分區

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

Sql代碼:
CREATE TABLE tk (
    col1 INT NOT NULL,
    col2 CHAR(5),
    col3 DATE
)
PARTITION BY LINEAR KEY (col1)
PARTITIONS 3;

在KEY分區中使用關鍵字LINEAR和在HASH分區中使用具有同樣的作用,分區的編號是通過2的冪(powers-of-two)算法得到,而不是通過模數算法。

源地址:http://www.xprogrammer.com/1653.html


########################################################################################

1.測試添加分區和刪除分區
###添加刪除range分區
(1)創建一個分區:
CREATE TABLE titles (
    emp_no      INT NOT NULL,
    title       VARCHAR(50)     NOT NULL,
    from_date   DATE            NOT NULL,
    to_date     DATE,
    KEY         (emp_no),
    PRIMARY KEY (emp_no,title, from_date)
) partition by range columns(from_date)
(partition p01 values less than ('1985-12-31'),
partition p02 values less than ('1990-12-31'),
partition p03 values less than ('1995-12-31'),
partition p04 values less than ('2000-12-31'),
partition p05 values less than ('2005-12-31'),
partition p06 values less than ('2010-12-31'),
partition p07 values less than ('2015-12-31'),
partition p08 values less than ('2020-12-31'),
partition p09 values less than ('2025-12-31'),
partition p10 values less than ('2030-12-31')
);
導入數據
mysql> source titles.sql
 
(2)添加分區:
備註:不能超過p04的範圍,嚴格遞增每個分區,即最小不能小於前一個分區
下面新曾了兩個分區n01和n02
 alter table titles
 reorganize partition p04 into(
 partition n01 values less than('1997-12-31'),
 partition n02 values less than('1998-12-31'),
 partition p04 values less than('2000-12-31')
 );
 
(3)刪除分區:
刪除分區即刪除數據。
mysql> select count(*) from titles where from_date<'1985-12-31';
+----------+
| count(*) |
+----------+
|    18238 |
+----------+
1 row in set (0.09 sec)
 
mysql> alter table titles drop partition p01;
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0
 
mysql> select count(*) from titles where from_date<'1985-12-31';
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.04 sec)
 
###添加刪除list分區
(1)創建list分區
CREATE TABLE titles (
    emp_no      INT NOT NULL,
    title       VARCHAR(50)     NOT NULL,
    from_date   DATE            NOT NULL,
    to_date     DATE,
    KEY         (emp_no),
    PRIMARY KEY (emp_no,title, from_date)
) partition by list columns(title)
(
partition p0 values in ('Assistant Engineer'),
partition p1 values in ('Engineer'),
partition p2 values in ('Manager'),
partition p3 values in ('Senior Engineer'),
partition p4 values in ('Senior Staff'),
partition p5 values in ('Staff'),
partition p6 values in ('Technique Leader')
);
導入數據
titles.sql 是employees數據庫導出的數據
mysql> source titles.sql
 
(2)添加分區
mysql> alter table titles add partition(partition p7 values in('CEO'));
Query OK, 0 rows affected (0.07 sec)
Records: 0  Duplicates: 0  Warnings: 0
 
(3)刪除分區:
mysql> alter table titles drop partition p0;
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0
 
###添加刪除hash分區
(1)創建hash分區
CREATE TABLE titles (
    emp_no      INT NOT NULL,
    title       VARCHAR(50)     NOT NULL,
    from_date   DATE            NOT NULL,
    to_date     DATE,
    KEY         (emp_no),
    PRIMARY KEY (emp_no,title, from_date)
) partition by hash(emp_no)
partitions 4;
導入數據:
mysql> source titles.sql
 
(2)刪除hash分區
4個分區減少到兩個,4-2=2
mysql> alter table titles coalesce partition 2;
Query OK, 443308 rows affected (12.41 sec)
Records: 443308  Duplicates: 0  Warnings: 0
 
(3)添加hash分區
增加到5個,2+3=5
mysql> alter table titles add partition partitions 3;
Query OK, 443308 rows affected (11.54 sec)
Records: 443308  Duplicates: 0  Warnings: 0
 
###添加刪除key分區
(1)創建key分區
CREATE TABLE titles (
    emp_no      INT NOT NULL,
    title       VARCHAR(50)     NOT NULL,
    from_date   DATE            NOT NULL,
    to_date     DATE,
    KEY         (emp_no),
    PRIMARY KEY (emp_no,title, from_date)
) partition by key(emp_no)
partitions 4;
導入數據
mysql> source titles.sql
 
(2)刪除分區,同hash
mysql> alter table titles coalesce partition 2;
Query OK, 443308 rows affected (7.86 sec)
Records: 443308  Duplicates: 0  Warnings: 0
 
(3)添加分區,同hash
mysql> alter table titles add partition partitions 3;
Query OK, 443308 rows affected (6.17 sec)
Records: 443308  Duplicates: 0  Warnings: 0



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