當單表資料量達到千萬級,查詢效能明顯下降。除分表、分庫、業務拆分外,表分區是維護成本最低、代碼改動最小的方案。本文系統整理 MySQL 5.1+ 分區功能:支援檢查、五大分區類型、建立語法、子分區、索引限制與實戰建議。
-- MySQL 5.6 之前
SHOW VARIABLES LIKE '%partition%';
-- have_partition_engine = YES 表示支援
-- MySQL 5.6 及之後
SHOW PLUGINS;
-- partition | ACTIVE | STORAGE ENGINE 表示已啟用
將表的不同行依規則存放於不同物理檔案,甚至不同磁碟。垂直分區(欄位拆分)不支援。
CREATE TABLE `T_part` (
`f_id` INT DEFAULT NULL,
`f_name` VARCHAR(20) DEFAULT NULL,
PRIMARY KEY (`f_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
PARTITION BY RANGE (f_id) (
PARTITION p0 VALUES LESS THAN (10),
PARTITION p1 VALUES LESS THAN (20)
);
f_id < 10 → p0;10 ≤ f_id < 20 → p1f_id ≥ 20 會報錯,需加 PARTITION p2 VALUES LESS THAN MAXVALUE 兜底-- 新增分區
ALTER TABLE T_part ADD PARTITION (PARTITION p2 VALUES LESS THAN (MAXVALUE));
-- 刪除分區(資料同步刪除!)
ALTER TABLE T_part DROP PARTITION p2;
| 類型 | 適用場景 | 語法關鍵字 |
|---|---|---|
| RANGE | 連續區間:時間、ID 範圍 | PARTITION BY RANGE(expr) + VALUES LESS THAN |
| LIST | 離散值集合:性別、狀態碼、地區代碼 | PARTITION BY LIST(expr) + VALUES IN (...) |
| HASH | 資料均勻分佈,無明確範圍 | PARTITION BY HASH(expr) + PARTITIONS N |
| LINEAR HASH | 大量資料時更優的修剪效能 | PARTITION BY LINEAR HASH(expr) |
| KEY | 由 MySQL 內部哈希函數計算,支援非整數欄位 | PARTITION BY KEY(col) + PARTITIONS N |
CREATE TABLE range_p (
perid INT, pername CHAR(12), monsalary DECIMAL(10,2), credate DATETIME
) PARTITION BY RANGE (YEAR(credate)) (
PARTITION p2011 VALUES LESS THAN (2011),
PARTITION p2012 VALUES LESS THAN (2012),
PARTITION p2013 VALUES LESS THAN (2013),
PARTITION p2014 VALUES LESS THAN (2014),
PARTITION p2015 VALUES LESS THAN MAXVALUE
);
CREATE TABLE list_p (
perid INT, pername CHAR(12), sex INT, monsalary DECIMAL(10,2), credate DATETIME
) PARTITION BY LIST (sex) (
PARTITION psex1 VALUES IN (1),
PARTITION psex2 VALUES IN (2)
);
注意: LIST 僅支援整數值,字串會報錯 ERROR 1697。
-- HASH
CREATE TABLE hash_p (...) PARTITION BY HASH(perid) PARTITIONS 8;
-- 或按年份哈希
CREATE TABLE hash_p (...) PARTITION BY HASH(YEAR(credate)) PARTITIONS 8;
-- KEY(MySQL 內建哈希,支援多欄位)
CREATE TABLE key_p (...) PARTITION BY KEY(perid) PARTITIONS 8;
CREATE TABLE key_p (...) PARTITION BY LINEAR KEY(perid) PARTITIONS 3;
CREATE TABLE T_part (
f_id INT, f_name VARCHAR(20), PRIMARY KEY (f_id)
) PARTITION BY RANGE (f_id)
SUBPARTITION BY HASH(f_id) SUBPARTITIONS 2 (
PARTITION p0 VALUES LESS THAN (10),
PARTITION p1 VALUES LESS THAN (20)
);
實際產生 2×2=4 個物理分區。可進一步指定每個子分區的資料/索引目錄分離至不同磁碟:
SUBPARTITION s0 DATA DIRECTORY='/disk0/data' INDEX DIRECTORY='/disk0/idx', ...
A PRIMARY KEY MUST INCLUDE ALL COLUMNS IN THE TABLE'S PARTITIONING FUNCTIONNOT NULLCREATE TABLE range_p (...)
PARTITION BY RANGE COLUMNS (credate) (
PARTITION p20151 VALUES LESS THAN ('2015-04-01'),
PARTITION p20152 VALUES LESS THAN ('2015-07-01'),
PARTITION p20153 VALUES LESS THAN ('2015-10-01'),
PARTITION p20154 VALUES LESS THAN ('2016-01-01'),
PARTITION partlog VALUES LESS THAN MAXVALUE
);
優化器根據 WHERE 條件中的分區鍵,僅掃描相關分區。務必在 WHERE 子句包含分區鍵,否則退化為全表掃描。
DROP PARTITION 秒級完成,避免大量 DELETE 鎖表