針對Mysql數據庫,表分區類型簡析。算法
【1】表分區類型sql
(1)Range分區:按範圍分區。按列值的範圍區間進行分區存儲;好比:id小於10存儲在一個分區;id大於10小於20存儲在另一個分區;數據庫
(2)List分區:按離散值集合分區。與range分區相似,不過它是按離散值進行分區。函數
(3)Hash分區:按hash算法結果分區。對用戶定義的表達式所返回的hash值來進行分區。學習
能夠寫partitions num(分區數目),或直接使用分區語句,好比partition p0 values in … ..ui
根據分區算法的不一樣,Hash分區分爲通常(取模法)Hash分區和線性(線性Hash規則,詳見下線性hash分區內容)Hash分區。spa
(4)Key分區:Key分區相似於Hash分區,不一樣點以下: 3d
[1] Key分區容許多列,而Hash分區只容許一列。code
[2] 若是在有主鍵或者惟一鍵的狀況下,Key中分區列可不指定,默認爲主鍵或者惟一鍵;若是沒有,則必須顯性指定列。對象
[3] Key分區對象必須爲列,而不能是基於列的表達式。
[4] Key分區和Hash分區的算法不同。PARTITION BY HASH (expr),MOD取值的對象是expr返回的值,而PARTITION BY KEY (column_list),基於列的MD5值。
(5)子分區:在一級分區的基礎上,再進行分區後才存儲。
【2】Range分區
Range分區建立表SQL語句:
-- ----------------------------BEGIN RANGE--------------------- -- 按Range範圍分區 -- [1]刪除舊錶 DROP TABLE `t_partition_by_range`; -- [2]建立新表 CREATE TABLE `t_partition_by_range` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `sName` VARCHAR(10) NOT NULL, `sAge` INT(2) UNSIGNED ZEROFILL NOT NULL, `sAddr` VARCHAR(20) DEFAULT NULL, `sGrade` INT(2) DEFAULT NULL, `sStuId` INT(8) DEFAULT NULL, `sSex` INT(1) UNSIGNED DEFAULT NULL ) ENGINE = INNODB PARTITION BY RANGE(id) ( PARTITION p0 VALUES LESS THAN(5), PARTITION p1 VALUES LESS THAN(10), PARTITION p2 VALUES LESS THAN(15) ); -- [3]添加源數據 INSERT INTO t_partition_by_range (sName, sAge, sAddr, sGrade, sStuId, sSex) VALUES ('wangchao', 8, 'heyang', 1, 1801111, 0), ('suntao', 9, 'weinan', 3, 1803110, 1), ('liuyan', 16, 'hancheng', 2, 20190211, 0), ('xuhui', 22, 'hancheng', 4, 201904107, 1), ('wangqi', 18, 'xian', 10, 201910104, 1), ('baihua', 16, 'nanjing', 8, 201908105, 1), ('xiaoping', 15, 'shenzhen', 6, 20190603, 1); -- [4]查詢分區信息 SELECT PARTITION_NAME, TABLE_ROWS, PARTITION_METHOD, PARTITION_EXPRESSION, PARTITION_DESCRIPTION, PARTITION_ORDINAL_POSITION FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't_partition_by_range'; -- ----------------------------END RANGE---------------------
分區存儲信息結果:
如上表,理論與實際結合分析:
把id < 5的4個實體(wangchao、suntao、liuyan、xuhui)存儲在分區p0;
把5 < id < 10的3個實體(wangqi、baihua、xiaoping)存儲在分區p1;
把10 < id < 15的實體會存儲在分區p2;
【3】List分區
List分區建立表SQL語句:
-- ----------------------------BEGIN LIST--------------------- -- 按List範圍分區 -- [1]刪除舊錶 DROP TABLE `t_partition_by_list`; -- [2]建立新表 CREATE TABLE `t_partition_by_list` ( `id` INT AUTO_INCREMENT , `sName` VARCHAR(10) NOT NULL, `sAge` INT(2) UNSIGNED ZEROFILL NOT NULL, `sAddr` VARCHAR(20) DEFAULT NULL, `sGrade` INT(2) NOT NULL, `sStuId` INT(8) DEFAULT NULL, `sSex` INT(1) UNSIGNED DEFAULT NULL, PRIMARY KEY (`id`, `sGrade`) ) ENGINE = INNODB PARTITION BY LIST(sGrade) ( PARTITION p0 VALUES IN(1, 3), PARTITION p1 VALUES IN(2, 4, 6), PARTITION p3 VALUES IN(10) ); -- [3]添加源數據 INSERT INTO t_partition_by_list (sName, sAge, sAddr, sGrade, sStuId, sSex) VALUES ('wangchao', 8, 'heyang', 1, 1801111, 0), ('suntao', 9, 'weinan', 3, 1803110, 1), ('liuyan', 16, 'hancheng', 2, 20190211, 0), ('xuhui', 22, 'hancheng', 4, 201904107, 1), ('wangqi', 18, 'xian', 10, 201910104, 1), ('baihua', 16, 'nanjing', 1, 201908105, 1), ('xiaoping', 15, 'shenzhen', 6, 20190603, 1); -- [4]查詢分區信息 SELECT PARTITION_NAME, TABLE_ROWS, PARTITION_METHOD, PARTITION_EXPRESSION, PARTITION_DESCRIPTION, PARTITION_ORDINAL_POSITION FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't_partition_by_list'; -- ----------------------------END LIST---------------------
分區存儲信息結果:
如上表,理論與實際結合分析:
把班級sgrade歸屬於離散值集合爲(一、3)的3個實體(wangchao、suntao、baihua)存儲在分區p0;
把班級sgrade歸屬於離散值集合爲(二、四、6)的3個實體(liuyan、xuhui、xiaoping)存儲在分區p1;
把班級sgrade歸屬於離散值集合爲(10)的1個實體(wangqi)存儲在分區p2;
另外,關於list分區表,尤爲注意:當分區字段的值不歸屬於任何一個離散值集合時,數據會插入失敗!
好比:插入源數據SQL語句:
INSERT INTO t_partition_by_list (sName, sAge, sAddr, sGrade, sStuId, sSex) VALUES ('wangchao', 8, 'heyang', 1, 1801111, 0), ('suntao', 9, 'weinan', 3, 1803110, 1), ('liuyan', 16, 'hancheng', 2, 20190211, 0), ('xuhui', 22, 'hancheng', 4, 201904107, 1), ('wangqi', 18, 'xian', 10, 201910104, 1), ('baihua', 16, 'nanjing', 8, 201908105, 1), ('xiaoping', 15, 'shenzhen', 6, 20190603, 1);
插入失敗,失敗信息以下:
查詢:INSERT INTO t_partition_by_list (sName, sAge, sAddr, sGrade, sStuId, sSex) VALUES ('wangchao', 8, 'heyang', 1, 1801111, 0), ('su...錯誤代碼: 1526
Table has no partition for value 8
【4】Hash分區
(1)通常Hash分區
Hash分區建立表SQL語句:
-- ----------------------------BEGIN HASH--------------------- -- 按Hash值分區 -- [1]刪除舊錶 DROP TABLE `t_partition_by_hash`; -- [2]建立新表 CREATE TABLE `t_partition_by_hash` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `sName` VARCHAR(10) NOT NULL, `sAge` INT(2) UNSIGNED ZEROFILL NOT NULL, `sAddr` VARCHAR(20) DEFAULT NULL, `sGrade` INT(2) NOT NULL, `sStuId` INT(8) DEFAULT NULL, `sSex` INT(1) UNSIGNED DEFAULT NULL ) ENGINE = INNODB PARTITION BY HASH(id) PARTITIONS 4; -- [3]添加源數據 INSERT INTO t_partition_by_hash (sName, sAge, sAddr, sGrade, sStuId, sSex) VALUES ('wangchao', 8, 'heyang', 3, 1803111, 0), ('suntao', 9, 'weinan', 6, 1806110, 1), ('liuyan', 16, 'hancheng', 8, 20190811, 0), ('xuhui', 22, 'hancheng', 12, 201912107, 1), ('wangqi', 18, 'xian', 11, 201911104, 1), ('baihua', 16, 'nanjing', 10, 201910105, 1), ('xiaoping', 15, 'shenzhen', 9, 20190103, 1); -- [4]查詢分區信息 SELECT PARTITION_NAME, TABLE_ROWS, PARTITION_METHOD, PARTITION_EXPRESSION, PARTITION_DESCRIPTION, PARTITION_ORDINAL_POSITION FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't_partition_by_hash'; -- ----------------------------END HASH---------------------
分區存儲信息結果:
如上表,理論與實際結合分析:咱們知道,通常狀況下(非通常狀況好比線性hash),hash分區使用的哈希函數爲求模數。
那咱們先利用Mysql的求模數函數分析一下,執行SQL以下:
SELECT id, MOD(id, 4) AS p_index FROM t_partition_by_hash ORDER BY id;
結果以下圖:
如今再結合上圖分區信息的結果,咱們得知:
把id哈希值爲0的1個實體(xuhui)存儲在分區p0;
把id哈希值爲1的2個實體(wangchao、wangqi)存儲在分區p1;
把id哈希值爲2的2個實體(suntao、baihua)存儲在分區p2;
把id哈希值爲3的2個實體(liuyan、xiaoping)存儲在分區p3;
好的,分析至此,咱們查詢一下數據存儲的實際狀況:
SQL語句以下:
SELECT * FROM t_partition_by_hash;
執行結果以下圖:
如上圖,查詢時,數據庫引擎會按照分區順序p0~p3依次讀取到各個分區的數據內容。
(2)線性Hash分區
線性Hash分區建立表SQL語句:
-- ----------------------------BEGIN LINEAR HASH--------------------- -- 按Linear Hash值分區 -- [1]刪除舊錶 DROP TABLE `t_partition_by_linear_hash`; -- [2]建立新表 CREATE TABLE `t_partition_by_linear_hash` ( `id` INT NOT NULL, `sName` VARCHAR(10) NOT NULL, `sAge` INT(2) UNSIGNED ZEROFILL NOT NULL, `sAddr` VARCHAR(20) DEFAULT NULL, `sGrade` INT(2) NOT NULL, `sStuId` INT(8) DEFAULT NULL, `sSex` INT(1) UNSIGNED DEFAULT NULL ) ENGINE = INNODB PARTITION BY LINEAR HASH(sGrade) PARTITIONS 6; -- [3]添加源數據 INSERT INTO t_partition_by_linear_hash (id, sName, sAge, sAddr, sGrade, sStuId, sSex) VALUES (1, 'wangchao', 8, 'heyang', 3, 1803111, 0), (2, 'suntao', 9, 'weinan', 6, 1806110, 1), (3, 'liuyan', 16, 'hancheng', 8, 20190811, 0), (4, 'xuhui', 22, 'hancheng', 12, 201912107, 1), (5, 'wangqi', 18, 'xian', 11, 201911104, 1), (6, 'baihua', 16, 'nanjing', 10, 201910105, 1), (7, 'xiaoping', 15, 'shenzhen', 9, 20190103, 1); -- [4]查詢分區信息 SELECT PARTITION_NAME, TABLE_ROWS, PARTITION_METHOD, PARTITION_EXPRESSION, PARTITION_DESCRIPTION, PARTITION_ORDINAL_POSITION FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't_partition_by_linear_hash'; -- ----------------------------END LINEAR HASH---------------------
分區存儲信息結果:
學習一下線性Hash分區的規則:
假設分區個數num = 6, 那麼N表示數據最終存儲的分區:
[1] 第一步,肯定V值
V值計算公式:V = POWER(2, CEILING(LOG(2, num)))
LOG()是計算num以2爲底的對數,CEILING()是向上取整,POWER()是取2的次方值。
假設num的值是2的倍數那麼這個表達式計算出來的結果不變。
V = POWER(2, CEILING(LOG(2, 6)))
V = POWER(2, 3)
V = 8
[2] 第二步,計算N值
N值計算公式:N = values & (V - 1)
&位與運算,將兩個值都轉換成二進制進行求與運算。
N = values & (V - 1)
N = 3 & (8 - 1)
N = 3 & 7
N = 3
[3] 第三步(當N >= num場景)
由於分區個數爲num,那麼,當N >= num時,顯然分區仍未知,須要再求N值:
N值計算公式:N = N & (CEIL(V / 2) - 1)
N = 6 & (CEIL(8 / 2) - 1)
N = 6 & 3
N = 2
因爲2不大於或等於6,因此能夠肯定存儲在分區p2。
依據以上規則,下面首先,咱們計算一級分區存儲索引號,SQL語句以下:
SELECT id, sGrade & (POWER(2, CEILING(LOG(2, 6))) - 1) AS p_index FROM t_partition_by_linear_hash ORDER BY id;
結果以下圖:
很明顯,id爲2的實體,一級N值爲6,須要進行第三步再確認,經規則示例分析,再確認結果應該爲2。
好的,至此爲止,咱們已經分析完成,驗證源數據存儲實際狀況,結果以下圖:
經驗證,可知:
sGrade爲8(id爲3)的實體被存儲在分區p0;
sGrade爲9(id爲7)的實體被存儲在分區p1;
sGrade爲六、10(id爲二、6)的實體被存儲在分區p2;
sGrade爲三、11(id爲一、5)的實體被存儲在分區p3;
sGrade爲12(id爲4)的實體被存儲在分區p4;
綜上所述,實際與理論分析徹底一致。
【5】Key分區
Key分區建立表SQL語句:
-- ----------------------------BEGIN KEY----------------------- -- [1]刪除舊錶 DROP TABLE `t_partition_by_key`; -- [2]建立新表 CREATE TABLE `t_partition_by_key` ( `id` INT AUTO_INCREMENT, `sName` VARCHAR(10) NOT NULL, `sAge` INT(2) UNSIGNED ZEROFILL NOT NULL, `sAddr` VARCHAR(20) DEFAULT NULL, `sGrade` INT(2) NOT NULL, `sStuId` INT(8) DEFAULT NULL, `sSex` INT(1) UNSIGNED DEFAULT NULL, PRIMARY KEY (`id`, `sGrade`) ) ENGINE = INNODB PARTITION BY KEY(sGrade) PARTITIONS 6; -- [3]添加源數據 INSERT INTO t_partition_by_key (sName, sAge, sAddr, sGrade, sStuId, sSex) VALUES ('wangchao', 8, 'heyang', 3, 1803111, 0), ('suntao', 9, 'weinan', 3, 1803110, 1), ('liuyan', 16, 'hancheng', 8, 20190811, 0), ('xuhui', 22, 'hancheng', 8, 201908107, 1), ('wangqi', 18, 'xian', 10, 201910104, 1), ('baihua', 16, 'nanjing', 10, 201910105, 1), ('xiaoping', 15, 'shenzhen', 9, 20190903, 1); -- [4]查詢分區信息 SELECT PARTITION_NAME, TABLE_ROWS, PARTITION_METHOD, PARTITION_EXPRESSION, PARTITION_DESCRIPTION, PARTITION_ORDINAL_POSITION FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't_partition_by_key'; -- ----------------------------END KEY---------------------
分區存儲信息結果:
總結:從分區存儲信息結果可知,p2分區存儲了3個實體;p3分區存儲了2個實體;p5分區存儲了2個實體。的確已所有存儲。
鑑於目前只明確Key分區的規則是基於列的MD5值,但具體爲何7個實體分別放在了p二、p三、p5分區,細節分析未果,待再研究。
附加目前分析進展,MD5值以下圖:
查詢SQL語句:
SELECT id, sGrade, MD5(sGrade) FROM t_partition_by_key ORDER BY id;
結果集:
【6】子分區
子分區建立表SQL語句:
-- ----------------------------BEGIN SUB PARTITION--------------------- -- 按SUB PARTITION分區 -- [1]刪除舊錶 DROP TABLE `t_partition_by_subpart`; -- [2]建立新表 CREATE TABLE `t_partition_by_subpart` ( `id` INT AUTO_INCREMENT, `sName` VARCHAR(10) NOT NULL, `sAge` INT(2) UNSIGNED ZEROFILL NOT NULL, `sAddr` VARCHAR(20) DEFAULT NULL, `sGrade` INT(2) NOT NULL, `sStuId` INT(8) DEFAULT NULL, `sSex` INT(1) UNSIGNED DEFAULT NULL, PRIMARY KEY (`id`, `sGrade`) ) ENGINE = INNODB PARTITION BY RANGE(id) SUBPARTITION BY HASH(sGrade) SUBPARTITIONS 2 ( PARTITION p0 VALUES LESS THAN(5), PARTITION p1 VALUES LESS THAN(10), PARTITION p2 VALUES LESS THAN(15) ); -- [3]添加源數據 INSERT INTO t_partition_by_subpart (sName, sAge, sAddr, sGrade, sStuId, sSex) VALUES ('wangchao', 8, 'heyang', 3, 1803111, 0), ('suntao', 9, 'weinan', 3, 1803110, 1), ('liuyan', 16, 'hancheng', 8, 20190811, 0), ('xuhui', 22, 'hancheng', 8, 201908107, 1), ('wangqi', 18, 'xian', 10, 201910104, 1), ('baihua', 16, 'nanjing', 10, 201910105, 1), ('xiaoping', 15, 'shenzhen', 9, 20190903, 1); -- [4]查詢分區信息 SELECT PARTITION_NAME, TABLE_ROWS, PARTITION_METHOD, PARTITION_EXPRESSION, PARTITION_DESCRIPTION, PARTITION_ORDINAL_POSITION FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't_partition_by_subpart'; -- ----------------------------END SUB PARTITION---------------------
分區存儲信息結果:
如上表,理論與實際結合分析:
把id < 5的4個實體(wangchao、suntao、liuyan、xuhui)存儲在分區p0;
把5 < id < 10的3個實體(wangqi、baihua、xiaoping)存儲在分區p1;
把10 < id < 15的實體會存儲在分區p2;
按子分區再分析:
子分區爲hash分區,即以sGrade值取模值做爲分區索引號,查詢SQL以下:
SELECT id, sGrade, MOD(sGrade, 2) FROM t_partition_by_subpart ORDER BY id;
分區索引號結果以下圖:
id爲一、二、三、4的實體,按主range分區,應該歸屬於p0分區;再按子hash分區:
由於實體一、2(wangchao、suntao)的sGrade值均爲3,取模後值爲1,即存儲在p0的第二個子分區;
由於實體三、4(liuyan、xuhui)的sGrade值均爲8,取模後置爲0,即存儲在p0的第一個子分區;
id爲五、六、7的實體,按主range分區,應該歸屬於p1分區;再按子hash分區:
由於實體五、6(wangqi、baihua)的sGrade值均爲10,取模後值爲0,即存儲在p1的第一個子分區;
由於實體7(xiaoping)的sGrade值爲9,取模後值爲1,即存儲在p1的第二個子分區。
好的,分析至此,咱們查詢一下數據存儲的實際狀況:
SQL語句以下:
SELECT * FROM t_partition_by_subpart;
實際狀況:
如上圖,說明:
由於查詢時數據庫引擎會按照分區順序p0~p3依次讀取到各個分區(包括子分區)存儲的數據內容,可見與咱們的理論分析結果相符。
Good Good Study, Day Day Up.
順序 選擇 循環 總結