分區 是一種物理資料庫設計技術,將大型邏輯表拆分為多個物理分區,每個分區可獨立儲存、管理、維護。主要目的是 減少特定 SQL 操作的資料掃描量,縮短響應時間。
按 行 將表資料分散到不同分區,每個分區擁有完整的表結構(所有欄位)。
-- 範例:發票表按年份分區
CREATE TABLE invoices (
id INT, invoice_date DATE, amount DECIMAL(10,2)
)
PARTITION BY RANGE (YEAR(invoice_date)) (
PARTITION p2020 VALUES LESS THAN (2021),
PARTITION p2021 VALUES LESS THAN (2022),
PARTITION p2022 VALUES LESS THAN (2023),
PARTITION pmax VALUES LESS THAN MAXVALUE
);
優勢: 查詢特定年份時,優化器只掃描對應分區(分區裁剪),大幅減少 I/O。
將 不常用的大欄位(TEXT、BLOB、JSON)移至獨立表/分區,主表保留高頻欄位。
-- 主表:高頻存取欄位
CREATE TABLE products_main (
id INT PRIMARY KEY, sku VARCHAR(50), name VARCHAR(200), price DECIMAL(10,2)
);
-- 擴展表:低頻大欄位
CREATE TABLE products_detail (
product_id INT PRIMARY KEY,
description TEXT, -- 大文本
manual BLOB, -- 二進位手冊
FOREIGN KEY (product_id) REFERENCES products_main(id)
);
優勢: 主表行更窄,單頁容納更多行,緩衝池命中率提升,索引更小。
| 類型 | 關鍵字 | 分區依據 | 典型場景 |
|---|---|---|---|
| Range 分區 | PARTITION BY RANGE | 連續範圍值(日期、數值區間) | 歷史資料按年/月歸檔、時間序列 |
| List 分區 | PARTITION BY LIST | 離散值列表(地區、狀態碼) | 按城市、部門、狀態分區 |
| Hash 分區 | PARTITION BY HASH | 使用者定義運算式的 Hash 值 | 均勻分散熱點、無明顯範圍邏輯 |
| Key 分區 | PARTITION BY KEY | MySQL 內部 Hash(支援非整數欄位) | 主鍵/唯一鍵非整數時自動分區 |
| Composite 復合分區 | 子分區 | 一級分區 + 二級子分區 | Range + Hash:按月分區,每月再 Hash 4 個子分區 |
原理: 優化器根據 WHERE 條件,只掃描相關分區,忽略無關分區。
-- 僅掃描 p2022 分區
SELECT * FROM invoices WHERE invoice_date BETWEEN '2022-01-01' AND '2022-12-31';
-- EXPLAIN 觀察 partitions 欄位
EXPLAIN PARTITIONS SELECT * FROM invoices WHERE YEAR(invoice_date) = 2022;
-- 輸出 partitions: p2022 (只掃描 1 個分區,而非全表)
效果: 百萬級表查詢從秒級降至毫秒級,I/O 減少 90%+。
ALTER TABLE ... DROP PARTITION p2020; 瞬間完成,無需 DELETE 慢速回收空間ANALYZE PARTITION、OPTIMIZE PARTITION、CHECK PARTITION 針對單分區操作| 限制 | 說明 | 應對 |
|---|---|---|
| 分區鍵必須是主鍵/唯一鍵一部分 | 若表有 PK/UK,分區欄位必須包含在內 | 設計時將分區欄位加入 PK,或用唯一鍵替代 |
| 不支援外鍵 | 分區表不能有 FK,也不能被引用 | 應用層維護參考完整性 |
| 最大 8192 個分區 | MySQL 8.0 放寬至 8192 | 合理規劃,避免過度分區 |
| 全文索引限制 | 5.6 前不支援,8.0 完整支援 | 升級 8.0 或應用層搜尋 |
| 臨時表限制 | 某些複雜查詢無法使用分區裁剪 | 改寫 SQL、加強索引覆蓋 |
EXPLAIN PARTITIONS 確認只掃描目標分區MySQL 分區是 大表效能優化的利器,核心價值在於 分區裁剪加速查詢 與 分區級生命週期管理簡化運維。但分區非銀彈,需配合合理索引、SQL 改寫、硬體資源才能發揮最大效用。