MySQL中表分區(qū)的詳細介紹

mysql表分區(qū)和分庫分表一樣,都是為了提高數(shù)據(jù)庫的吞吐量。分區(qū)類似與分表,分表是邏輯上將一個大數(shù)據(jù)量的表分成多個,可以是水平分也可以是垂直分。而分區(qū)是將表的一個數(shù)據(jù)文件拆分成多個。不同的數(shù)據(jù)拆分到不同的文件中。這樣對于一個數(shù)據(jù)量非常大的表,有多個數(shù)據(jù)文件來進行存儲,這樣就提高了數(shù)據(jù)庫的 io 性能。

既然是針對的數(shù)據(jù)表的文件進行操作,那么我們就需要先來了解 mysql 表的存儲。我們知道,MySQL 有多種存儲引擎,不同的存儲引擎所存儲的文件格式不同。這里主要以 InnoDB 和 MyISAM 這兩種存儲引擎來說明。

InnoDB

.frm 文件 數(shù)據(jù)表的結(jié)構(gòu)

.idb 文件 表的數(shù)據(jù)文件,獨享表空間,每個表有一個.idb 文件

.ibdata 文件 表的數(shù)據(jù)文件,共享表空間,所有的表使用這一個數(shù)據(jù)

文件

MyISAM

.frm 文件 數(shù)據(jù)表的結(jié)構(gòu)

.myd 文件 數(shù)據(jù)文件

.myi 文件 索引文件

?MySQL中表分區(qū)的詳細介紹

首先要查看一下我們當前的數(shù)據(jù)庫版本是否支持分區(qū)

1?show?variables?like?'%partition%';

如何進行分區(qū)呢?在進行數(shù)據(jù)庫水平切分的時候我們知道,水平切分可以根據(jù)指定字段取模的方式來分到不同的表中,也可以根據(jù)日期來進行切分,或者根據(jù) id 來分段,1-100 萬在第一張表中,100 萬零 1 到 200 萬在第二張表中以此類推等等。總之我們在進行切分的過程中有很多的途徑。那么在表分區(qū)上數(shù)據(jù)庫也給我們提供了多種方案可供我們選擇。

?

MySQL 表分區(qū)策略

RANGE 分區(qū) 基于屬于一個給定連續(xù)區(qū)間的列值,把多行分配給分區(qū)

1?DROP?TABLE?IF?EXISTS?`p_range`;  2?CREATE?TABLE?`p_range`?(  3?`id`?int(10)?NOT?NULL?AUTO_INCREMENT,  4?`name`?char(20)?NOT?NULL,  5?PRIMARY?KEY?(`id`)  6?)?ENGINE=MyISAM?AUTO_INCREMENT=9?DEFAULT?CHARSET=utf8  7?/*!50100?PARTITION?BY?RANGE?(id)  8?(PARTITION?p0?VALUES?LESS?THAN?(8)?ENGINE?=?MyISAM)?*/;

最大值

1?PARTITION?BY?RANGE?(id)  2?(  3?PARTITION?p0?VALUES?LESS?THAN?(8),  4?PARTITION?p1?VALUES?LESS?THAN?MAXVALUE)

適用場景:

這樣就表示,所有 id 大于 7 的數(shù)據(jù)記錄存在在 p1 分區(qū)里。

RANGE 分區(qū)在如下場合特別有用:

·當需要刪除“舊的”數(shù)據(jù)時。如果你使用上面最近的那個例子給出的分區(qū)方案,你只需簡單地使用 “ALTER TABLE employees DROP PARTITION p0;”來刪除所有在 1991 年前就已經(jīng)停止工作的雇員相對應(yīng)的所有行。對于有大量行的表,這比運行一個如“DELETE FROM employees WHERE YEAR(separated)

1990;”這樣的一個 DELETE 查詢要有效得多。

·想要使用一個包含有日期或時間值,或包含有從一些其他級數(shù)開始增長的值的列。

·經(jīng)常運行直接依賴于用于分割表的列的查詢。例如,當執(zhí)行一個如

“SELECT?COUNT(*)?FROM?employees?WHERE?YEAR(separated)?=?2000?GROUP?BY?store_id;”

這樣的查詢時,MySQL 可以很迅速地確定只有分區(qū) p2 需要掃描,這是因為余下的分區(qū)不可能包含有符合該 WHERE 子句的任何記錄

?

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

1?DROP?TABLE?IF?EXISTS?`p_list`;  2?CREATE?TABLE?`p_list`?(  3?`id`?int(10)?NOT?NULL?AUTO_INCREMENT,  4?`typeid`?mediumint(10)?NOT?NULL?DEFAULT?'0',  5?`typename`?char(20)?DEFAULT?NULL,  6?PRIMARY?KEY?(`id`,`typeid`)  7?)?ENGINE=MyISAM?AUTO_INCREMENT=9?DEFAULT?CHARSET=utf8  8?/*!50100?PARTITION?BY?LIST?(typeid)  9?(PARTITION?p0?VALUES?IN?(1,2,3,4)?ENGINE?=?MyISAM,?PARTITION?p1?VALUES?IN?(5,6,7,8)?ENGINE?=?MyISAM)?*/;

HASH 分區(qū) ?基于用戶定義的表達式的返回值來進行選擇的分區(qū),該表達式使用將要插入到表中的這些行的列值進行計算。這個函數(shù)可以包含 MySQL 中有效的、產(chǎn)生非負整數(shù)值的任何表達式。 HASH 分區(qū)主要用來確保數(shù)據(jù)在預先確定數(shù)目的分區(qū)中平均分布。在 RANGE 和 LIST 分區(qū)中,必須明確指定一個給定的列值或列值集合應(yīng)該保存在哪個分區(qū)中;而在 HASH 分區(qū)中,MySQL 自動完成這些工作,你所要做的只是基于將要被哈希的列值指定一個列值或表達式,以及指定被分區(qū)的表將要被分割成的分區(qū)數(shù)量

1?DROP?TABLE?IF?EXISTS?`p_hash`;  2?CREATE?TABLE?`p_hash`?(  3?`id`?int(10)?NOT?NULL?AUTO_INCREMENT,  4?`storeid`?mediumint(10)?NOT?NULL?DEFAULT?'0',  5?`storename`?char(255)?DEFAULT?NULL,  6?PRIMARY?KEY?(`id`,`storeid`)  7?)?ENGINE=InnoDB?AUTO_INCREMENT=11?DEFAULT?CHARSET=utf8  8?/*!50100?PARTITION?BY?HASH?(storeid)9?PARTITIONS?4?*/;

簡單點說就是數(shù)據(jù)的存入可以按 partition by hash(expr); 這里的 expr 可以

是鍵名也可以是表達式比如 YEAR(time),如果是表達式的情況下

“但是應(yīng)當記住,每當插入或更新(或者可能刪除)一行,這個表達式都要計

算一次;這意味著非常復雜的表達式可能會引起性能問題,尤其是在執(zhí)行同時

影響大量行的運算(例如批量插入)的時候。 ”

在執(zhí)行刪除、寫入、更新時這個表達式都會計算一次。

數(shù)據(jù)的分布采用基于用戶函數(shù)結(jié)果的模數(shù)來確定使用哪個編號的分區(qū)。換句話,對于一個表達式“expr”,將要保存記錄的分區(qū)編號為 N ,其中“N = MOD(expr, num)”。

比如上面的 storeid 為 10;那么 N=MOD(10,4) ;N 是等于 2 的,那么這條記錄就存儲在 p2 的分區(qū)里面。

如果插入一個表達式列值為’2005-09-15′的記錄到表中,那么保存該條記錄的分區(qū)確定如下:MOD(YEAR(‘2005-09-01′),4) = MOD(2005,4) = 1 ; 就存儲在 p1 分區(qū)里面了。

?

分區(qū)注意點

1、重新分區(qū)時,如果原分區(qū)里面存在 maxvalue 則新的分區(qū)里面也必須包含

maxvalue 否則就錯誤。

alter?table?p_range2x  reorganize?partition?p1,p2  into?(partition?p0?values?less?than?(5),?partition?p1?values?less?than?maxvalue);  [Err]?1520?–?Reorganize?of?range?partitions?cannot?change?total?ranges?except?for?last?partition?where?it?can?extend?the?range

2、分區(qū)刪除時,數(shù)據(jù)也同樣會被刪除 alter table p_range drop partition p0;

3、如果 range 分區(qū)列表里面沒有 maxvalue 則如有新數(shù)據(jù)大于現(xiàn)在分區(qū) range 數(shù)據(jù)值那么這個數(shù)據(jù)是無法寫入到數(shù)據(jù)庫表的。

?

4、修改表名不需要 刪除分區(qū)后在進行更改,修改表名后分區(qū)存儲 myd myi 對應(yīng)也會自動更改。

?

如果希望從所有分區(qū)刪除所有的數(shù)據(jù),但是又保留表的定義和表的分區(qū)模式,使用 TRUNCATE TABLE 命令。(請參見 13.2.9 節(jié),“TRUNCATE 語法”)。

?

如果希望改變表的分區(qū)而又不丟失數(shù)據(jù),使用“ALTER TABLE … REORGANIZE PARTITION”語句。參見下面的內(nèi)容,或者在 13.1.2 節(jié),“ALTER TABLE 語法” 中參考關(guān)于 REORGANIZE PARTITION 的信息。

?

5、對表進行分區(qū)時,不論采用哪種分區(qū)方式如果表中存在主鍵那么主鍵必須在分區(qū)列中。表分區(qū)的局限性。

?

6、list 方式分區(qū)沒有類似于 range 那種 less than maxvalue 的寫法,也就是說 list 分區(qū)表的所有數(shù)據(jù)都必須在分區(qū)字段的值列表集合中。

?

7、在 MySQL 5.1 版中,同一個分區(qū)表的所有分區(qū)必須使用同一個存儲引擎;例如,不能對一個分區(qū)使用 MyISAM,而對另一個使用 InnoDB。

?

8、分區(qū)的名字是不區(qū)分大小寫的,myp1 與 MYp1 是相同的。

??

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點贊5 分享