MySQL 5.5 引入 **COLUMNS 分區**,支援整數、日期、字串型別直接分區,**無需函數轉換**,並支援多欄位組合分區鍵。本文詳細解析 RANGE COLUMNS 與 LIST COLUMNS 語法、多欄位比較規則、執行計劃驗證與遷移建議。
| 特性 | 傳統 RANGE/LIST | COLUMNS 分區 |
|---|---|---|
| 日期分區 | 需 YEAR(date_col) 函數轉整數 | 直接 PARTITION BY RANGE COLUMNS(date_col) |
| 字串分區 | 不支援 | 支援 CHAR/VARCHAR/BINARY/VARBINARY |
| 多欄位分區鍵 | 不支援 | 支援 (如 RANGE COLUMNS(a,b)) |
| 表達式分區鍵 | 支援 | **不支援** |
CREATE TABLE members (
id INT, joined DATE NOT NULL
) PARTITION BY RANGE COLUMNS(joined) (
PARTITION a VALUES LESS THAN ('1960-01-01'),
PARTITION b VALUES LESS THAN ('1970-01-01'),
PARTITION c VALUES LESS THAN ('1980-01-01'),
PARTITION d VALUES LESS THAN ('1990-01-01'),
PARTITION e VALUES LESS THAN MAXVALUE
);
INSERT INTO members(id,joined) VALUES
(1,'1950-01-01'),(1,'1960-01-01'),(1,'1980-01-01'),(1,'1990-01-01');
SELECT PARTITION_NAME, PARTITION_METHOD, PARTITION_EXPRESSION,
PARTITION_DESCRIPTION, TABLE_ROWS
FROM information_schema.PARTITIONS
WHERE TABLE_SCHEMA=SCHEMA() AND TABLE_NAME='members';

EXPLAIN SELECT id,joined FROM members WHERE joined=YEAR(NOW()); -- partitions: ALL (使用函數導致無法裁剪) EXPLAIN SELECT id,joined FROM members WHERE joined='1963-01-01'; -- partitions: b (精準裁剪到 b 分區)

結論:分區欄位**嚴禁使用函數/運算**,否則失效全表掃描。
CREATE TABLE rcx ( a INT, b INT ) PARTITION BY RANGE COLUMNS(a,b) ( PARTITION p0 VALUES LESS THAN (5,10), PARTITION p1 VALUES LESS THAN (10,20), PARTITION p2 VALUES LESS THAN (15,30), PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE) );
多欄位比較規則(元組比較):
範例驗證:
INSERT INTO rcx(a,b) VALUES (1,20), (10,15), (10,30); -- (1,20): 1<5 → p0 -- (10,15): 10>5, 10=10 且 15<20 → p1 -- (10,30): 10=10 但 30>20 → 不屬 p1;10<15 → p2

限制:第一欄位分區界值**必須單調遞增**,不可交叉(如 p2 第一欄位 8 < p1 的 10 會報錯);第二欄位無順序要求。
CREATE TABLE listvar (
id INT NOT NULL, hired DATETIME NOT NULL
) PARTITION BY LIST COLUMNS(hired) (
PARTITION a VALUES IN ('1990-01-01 10:00:00','1991-01-01 10:00:00'),
PARTITION b VALUES IN ('1992-01-01 10:00:00'),
PARTITION c VALUES IN ('1993-01-01 10:00:00'),
PARTITION d VALUES IN ('1994-01-01 10:00:00')
);
ALTER TABLE listvar ADD INDEX ix_hired(hired);
INSERT INTO listvar VALUES
(1,'1990-01-01 10:00:00'),(1,'1991-01-01 10:00:00'),
(1,'1992-01-01 10:00:00'),(1,'1993-01-01 10:00:00');
EXPLAIN SELECT * FROM listvar WHERE hired='1990-01-01 10:00:00';
-- partitions: a (精準裁剪)

CREATE TABLE listvardou ( id INT NOT NULL, hired DATETIME NOT NULL ) PARTITION BY LIST COLUMNS(id,hired) ( PARTITION a VALUES IN ((1,'1990-01-01 10:00:00'),(1,'1991-01-01 10:00:00')), PARTITION b VALUES IN ((2,'1992-01-01 10:00:00')), PARTITION c VALUES IN ((3,'1993-01-01 10:00:00')), PARTITION d VALUES IN ((4,'1994-01-01 10:00:00')) ); ALTER TABLE listvardou ADD INDEX ix_hired1(id,hired); -- 組合索引最佳 EXPLAIN SELECT * FROM listvardou WHERE id=1 AND hired='1990-01-01 10:00:00'; -- filtered 100%,組合索引生效

ALTER TABLE tablename REMOVE PARTITIONING;
僅移除分區元數據,**不刪除數據**;DROP PARTITION 則會連同數據一併刪除。