MySQL 最常用的索引結構是 B-Tree (O(log n)),但在特定場景下 Hash 索引 (O(1)) 能帶來極致查詢效能。本文基於官方文檔深度解析兩者特徵差異、適用條件、MySQL 版本引擎支援現狀,並補充實戰避坑經驗。
| 特性 | B-Tree 索引 | Hash 索引 |
|---|---|---|
| 時間複雜度 | O(log n) | O(1) 理想情況 |
| 支援運算符 | =, >, >=, <, <=, BETWEEN, LIKE (前綴) | =, <=> (等值比較) |
| 範圍查詢 | 支援 | 不支援 |
| 排序支援 | 支援 ORDER BY | 不支援 (無序) |
| 最左前綴原則 | 適用 | 不適用 |
| 完整鍵查找 | 支援前綴查找 | 需完整鍵 |
| 統計資訊估算 | 可估算行數 | 無法估算範圍行數 |
-- 使用索引
WHERE col = 'value'
WHERE col > 'value'
WHERE col BETWEEN 10 AND 20
WHERE col LIKE 'abc%' -- 前綴固定
WHERE col LIKE 'ab_%' -- 模式固定前綴
-- 不使用索引
WHERE col LIKE '%abc' -- 萬用字元開頭
WHERE col LIKE '%abc%' -- 兩端萬用字元
WHERE col LIKE other_col -- 非常量
長字串 LIKE '%string%' (string > 3 字符) 會啟用 Turbo Boyer-Moore 算法優化。
WHERE col IS NULL -- 可使用索引
INDEX idx_a_b_c (a, b, c)
-- 可用到索引的查詢
WHERE a = 1
WHERE a = 1 AND b = 2
WHERE a = 1 AND b = 2 AND c = 3
WHERE a = 1 AND c = 3 -- 僅用到 a
-- 無法使用索引
WHERE b = 2
WHERE b = 2 AND c = 3
WHERE c = 3
-- 使用索引
WHERE a = 1 OR a = 2
WHERE a = 1 OR (b = 2 AND a = 3)
-- 不使用索引
WHERE a = 1 OR b = 2 -- a 有索引但 b 無
LIMIT 限制返回行數時,優化器傾向使用索引=、<=>,極快但功能受限ORDER BY、GROUP BY、範圍查詢| 引擎 | B-Tree | Hash | 備註 |
|---|---|---|---|
| InnoDB | ✅ 預設 | ❌ 不支援 | 自適應 Hash 索引 (AHI) 內部自動建立 |
| MyISAM | ✅ 預設 | ❌ 不支援 | |
| MEMORY | ✅ 可選 | ✅ 預設 | USING HASH / USING BTREE |
| NDB Cluster | ✅ | ✅ | 主鍵預設 Hash |
關鍵結論:InnoDB/MyISAM (最常用引擎) 僅支援 B-Tree。無法在主流業務表上直接建立 Hash 索引。
InnoDB 內建 Adaptive Hash Index:監控索引頁訪問模式,自動為熱門 B-Tree 頁建立記憶體 Hash 索引,加速等值查找。屬內部機制,用戶不可控,可透過 innodb_adaptive_hash_index=ON/OFF 開關。
USING HASHUSING BTREE-- 字符集亂碼問題:即使表設 utf8,連接也需設定
SET NAMES utf8mb4; -- 或 SET CHARACTER SET utf8mb4;
-- 建議在連接池配置 connectionInitSql 執行
B-Tree 是關係型資料庫索引的通用基石,功能完整、穩定可靠。Hash 索引雖理論 O(1) 極快,但受限於僅支援 MEMORY/NDB 引擎、不支援範圍查詢、無序、需完整鍵等硬性限制,在 InnoDB/MyISAM 主流業務場景無法直接使用。理解兩者邊界,合理設計 B-Tree 複合索引、善用覆蓋索引、引入 Redis 處理純鍵值熱點,才是實務中的正解。