數據庫分區:MySQL分區

1、什麼是分區?

單表數據庫本地文件爲下表所示:

存儲引擎 文件類型 存儲內容
MyISAM .frm 存放表結構,字段長度等
.myd 存儲數據信息
.myi 存儲索引信息
InnoDB .frm 存放表結構,字段長度等
.ibd 存儲數據信息和索引信息
如果一張表的數據量很大,那麼myd、myi或者ibd就會很大,讀寫就會很慢。 分區是將數據分段存放在多個位置,可以是不同的硬盤、系統,或者是不同服務器存儲介子中。分區後,在邏輯上還是一張表,但底層是由多個物理區塊組成。業務讀寫操作時還是原大表的名字,數據庫自動去組織分區的數據。

分區之後,數據文件被分成了很多塊,只要知道了所查數據在哪一塊,就可以在哪一塊上快速查找。

2、分類

RANGE分區:基於一個給定的不重疊的連續區間範圍的列值,把多行數據分配到不同的分區。比如:00-09年的數據、10-19年的數據、20年及以後的數據。
LIST分區:類似於range分區,區別在於list分區是基於列值匹配一個離散值集合中的某個值來進行選擇。比如:2019年的數據、2020年的數據。
HASH分區:通過對錶的一個或多個列的Hash Key進行計算,最後通過得到的Hash碼對應到不同的數據分區。
KEY分區:類似於hash分區,但是隻能使用MySQL服務器提供的哈希函數進行計算。

說明:(1)在MySQL5.1版本中,RANGE,LIST,HASH分區要求分區鍵必須是INT類型,或者通過表達式返回INT類型。但KEY分區的時候,可以使用其他類型的列(BLOB,TEXT類型除外)作爲分區鍵。
(2)如果表中存在主鍵或者唯一索引的列,那麼分區鍵中的列必須在主鍵或唯一索引中包括。否則會報錯1503。
(3)一個表最多只能有1024個分區。
(4)分區表中無法使用外鍵約束。
(5)RANGE分區將null值放在範圍最小的分區,LIST將其保存在0的分區;在按HASH和KEY分區的情況下,任何產生NULL值的表達式mysql都視同它的返回值爲0。爲了避免這種情況的產生,建議分區鍵設置成NOT NULL。

3、RANGE分區

(1)首先確認分區功能開啓
MySQL從5.1版本開始支持分區,5.6以下的版本:

show variables like '%partition%

會出現have_partitioning YES。
5.6以上的版本

show plugins;

在這裏插入圖片描述
出現partition ACTIVE

(2)創建表

DROP TABLE IF EXISTS test;
CREATE TABLE test (
	id INT(11) NOT NULL AUTO_INCREMENT,
	uid INT(11) NOT NULL,
	name VARCHAR(30) NOT NULL,
	placeid INT(11) NOT NULL,
	salary FLOAT,
  PRIMARY KEY(id, placeid)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
PARTITION BY RANGE (placeid)(
	PARTITION p0 VALUES LESS THAN (6),
	PARTITION p1 VALUES LESS THAN (11),
	PARTITION p2 VALUES LESS THAN (MAXVALUE)
);

注意這裏,因爲存在主鍵,所以用來分區的鍵必須包含在主鍵裏。;less than不能出現無法區分的情況,不如出現兩次less than (21)。
創建完成後,在mysql/data/separation目錄下可以看到,
在這裏插入圖片描述
其中.par文件存儲分區信息。
(3)插入數據

INSERT INTO test VALUES(1, 10001, '張三', 1, 5555.55);
INSERT INTO test VALUES(2, 10002, '李四', 3, 5555.55);
INSERT INTO test VALUES(3, 10003, '小六', 7, 6666.66);
INSERT INTO test VALUES(4, 10004, '王五', 13, 7000);
INSERT INTO test VALUES(5, 10005, '趙一', 24, 7000);

其中前兩條會插入p0,第三條插入p1,後兩條插入p2。
(4)根據時間劃分
根據TIMESTAMP範圍:

DROP TABLE IF EXISTS test_timestamp;
CREATE TABLE test_timestamp(
	id INT(11) NOT NULL,
	time TIMESTAMP
) ENGINE=MyISAM DEFAULT CHARSET=utf8
PARTITION BY RANGE (UNIX_TIMESTAMP(time))(
	PARTITION p0 VALUES LESS THAN (UNIX_TIMESTAMP('2019-12-31 00:00:00')),
	PARTITION p1 VALUES LESS THAN (UNIX_TIMESTAMP('2020-05-12 00:00:00')),
	PARTITION p2 VALUES LESS THAN (MAXVALUE)
);

根據DATE、DATETIME範圍:
添加COLUMNS關鍵字可以定義非INT類型,但是COLUMNS括號內只能是列名,不支持函數

DROP TABLE IF EXISTS test_date;
CREATE TABLE test_date(
	id INT(11) NOT NULL,
	time DATE
) ENGINE=MyISAM DEFAULT CHARSET=utf8
PARTITION BY RANGE COLUMNS(time)(
	PARTITION p0 VALUES LESS THAN ('2019-12-31'),
	PARTITION p1 VALUES LESS THAN ('2020-05-12'),
	PARTITION p2 VALUES LESS THAN (MAXVALUE)
);

這裏range(year(time))可以很方便的按年份分區。
(5)多列分區
COLUMNS關鍵字也可用於多列分區

DROP TABLE IF EXISTS test_columns;
CREATE TABLE test_columns (
	id INT(11) NOT NULL,
	uid INT(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8
PARTITION BY RANGE COLUMNS(id, uid)(
	PARTITION p0 VALUES LESS THAN (6, 10),
	PARTITION p1 VALUES LESS THAN (11, 20),
	PARTITION p2 VALUES LESS THAN (MAXVALUE, MAXVALUE)
);

注意這裏每一列只能出現一次MAXVALUE,出現多次會報錯1493。 在這裏插入圖片描述

4、LIST分區

和RANGE分區類似,不使用COLUMNS關鍵字時,只允許LIST括號內爲INT類型或返回INT類型的函數。
假設國內城市的city_id爲:1、3、7、11、19;國外城市的city_id爲:5、10、20。

DROP TABLE IF EXISTS test_list;
CREATE TABLE test_list (
	id INT(11) NOT NULL,
	city_id INT(11)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
PARTITION BY LIST (city_id)(
	PARTITION p_china VALUES IN (1, 3, 7, 11, 19),
	PARTITION p_foreign VALUES IN (5, 10, 20)
);

5、HASH分區

HASH分區主要用來確保數據在確定好的分區數目的分區中均勻分佈,實際上就是將整數對分區數取模後確定分區。

DROP TABLE IF EXISTS test_hash;
CREATE TABLE test_hash (
	id INT(11) NOT NULL,
	city_id INT(11)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
PARTITION BY HASH (city_id)
PARTITIONS 3;

HASH括號裏可以是整數也可以是返回整數的表達式;“PARTITIONS num”表示要被分割成分區的數量,如果沒有該語句,默認分區數量爲1。
另外將HASH替換爲LINEAR HASH:

PARTITION BY LINEAR HASH (city_id)

普通HASH(value)的計算過程比較簡單是:value%num,但是其擴展性差。LINEAR HASH的計算過程:

(1)V = POWER(2, CEILING(LOG(2, num))) 
這一步是找到第一個大於等於num的2的冪次整數;
POWER爲指數計算,CEILINGL爲向上取整運算,LOG爲對數運算;
(2)N = value & (V-1), &爲按位與操作;
(3)當N >= num:
		V = CEIL(V/2), N = N & (V-1), CEIL爲向下取整操作。

線性哈希分區的好處是增加,下降,合併,拆分分區可以更快,有利於在處理含有非常大量的數據表(百萬兆字節)。缺點是,與常規哈希分區獲得的分佈相比,分區之間不太可能均勻分佈數據。

6、KEY分區

KEY分區和HASH分區相似,只需要將HASH分區的HASH換爲KEY即可,區別是兩者的哈希函數不同。KEY分區中同樣可以使用LINEAR關鍵字。
另外當表存在主鍵或唯一索引時可省略Key括號內的列名,Mysql將按照主鍵-唯一索引的順序選擇,當找不到唯一索引時報錯1488。

DROP TABLE IF EXISTS test_key;
CREATE TABLE test_key (
	id INT(11) NOT NULL PRIMARY KEY,
	city_id INT(11)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
PARTITION BY KEY ()
PARTITIONS 3;

7、性能比較

以range分區爲例,採用range分區中(2)(3)創建的數據表test,未分區前,查詢placeid = 13的數據,可以看到搜索了5條數據,
在這裏插入圖片描述
而添加分區後,由於placeid = 13只可能存在於分區p2中,所以只需要搜索p2分區,搜索2條數據即可。現在因爲數據量少差距不大,當數據量很大時,分區能夠帶來很大程度的性能提升。
在這裏插入圖片描述

8、分區的管理

以range分區爲例,採用range分區中(2)(3)創建的數據表test。
(1)增加分區

ALTER TABLE test ADD PARTITION (PARTITION p3 VALUES LESS THAN (100));

(2)刪除分區

ALTER TABLE test DROP PARTITION p0;

刪除分區同時刪除該分區數據;不可刪除HASH分區和KEY分區。
(3)刪除全部分區

Alter TABLE test REMOVE PARTITIONING;

只清除所有分區,保留數據。
(4)修改分區

ALTER TABLE test PARTITION BY RANGE (placeid)(
	PARTITION p0 VALUES LESS THAN (6),
	PARTITION p1 VALUES LESS THAN (11),
	PARTITION p2 VALUES LESS THAN (16),
	PARTITION p3 VALUES LESS THAN (MAXVALUE)
);

若修改的是HASH分區或者KEY分區:

ALTER TABLE test_hash PARTITION BY HASH(city_id)PARTITIONS 7;

(5)拆分分區

ALTER TABLE test
REORGANIZE PARTITION p0 INTO
(
PARTITION p0_1 VALUES LESS THAN (3),
PARTITION p0_2 VALUES LESS THAN (6)
);

注意拆分後的總範圍應保持拆分前的範圍保持一致。
(6)合併分區

ALTER TABLE test
REORGANIZE PARTITION p0_1,p0_2 INTO
(
PARTITION p0 VALUES LESS THAN (6)
);

同樣需要注意合成後的範圍應該和合成前各分區的總範圍一致。
(7)重建分區

ALTER TABLE test REBUILD PARTITION p0,p1;

此操作和先刪除保存在分區的數據,然後重新插入它們具有相同的效果,可以用來整理分區碎片。
(8)優化分區

ALTER TABLE test OPTIMIZE PARTITION p0,p1;

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

和(7)(8)操作類似的還有:

ALTER TABLE test ANALYZE PARTITION p0,p1;   -- 分析分區
ALTER TABLE test REPAIR PARTITION p0,p1;   -- 修補分區
ALTER TABLE test CHECK PARTITION p0,p1;   -- 檢查分區
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章