首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL 索引學習教程:B+樹與Hash索引原理、適用場景、限制與建立策略

     編輯:MySQL 綜合教學

MySQL 索引學習教程:B+樹與 Hash 索引原理、適用場景、限制與建立策略

索引是 MySQL 查詢性能的核心引擎。本文系統講解 InnoDB 默認 B+樹索引與 Memory 引擎 Hash 索引的數據結構原理、適用查詢模式、硬性限制,並給出生產環境索引建立的三大策略與避坑清單。

一、 兩大索引類型架構對比

維度B+樹索引 (InnoDB/Default)Hash 索引 (Memory/HEAP)
數據結構平衡多路搜索樹 (所有數據在葉子節點,葉子雙向鏈表)哈希表 (Key → Value 直接映射)
查詢複雜度O(log N) 穩定O(1) 平均,最差 O(N) (衝突嚴重時)
支援操作等值、範圍、前綴、排序、分組、覆蓋索引**僅等值查詢** (=, IN, <=>)
排序能力天然有序,支援 ORDER BY/GROUP BY 避免 filesort無序,不支援排序
部分匹配支援最左前綴 (如 `LIKE 'abc%'`) 不支援部分匹配
範圍查詢支援 (>, <, >=, <=, BETWEEN)不支援
適用引擎InnoDB, MyISAMMemory, NDB Cluster
持久化磁盤持久化內存表重啟丟失 (需從磁盤表重建)

二、 B+樹索引可用的 6 大查詢模式

  1. 全值匹配:`WHERE id = 123` (主鍵/唯一索引點查,最快)
  2. 最左前綴匹配:聯合索引 `(a,b,c)`,查 `WHERE a=1` / `WHERE a=1 AND b=2` → 可用;查 `WHERE b=2` → **不可用**
  3. 列前綴匹配:`WHERE name LIKE 'Zhang%'` → 可用 (非 `%` 開頭)
  4. 範圍值查詢:`WHERE create_time > '2024-01-01' AND create_time < '2024-02-01'`
  5. 精確匹配左列 + 範圍匹配右列:`WHERE user_id = 100 AND create_time > '2024-01-01'` → `user_id` 走索引,`create_time` 走索引範圍掃描
  6. 覆蓋索引:查詢列全包含在索引中 → `Extra: Using index`,無需回表,性能倍增

三、 B+樹索引 4 大硬性限制 (必須背誦)

  1. 非最左列開頭查詢不可用:`INDEX(a,b,c)`,`WHERE b=1` 或 `WHERE c=1` 全表掃描
  2. 不能跳過中間列:`INDEX(a,b,c)`,`WHERE a=1 AND c=2` → 僅 `a` 走索引,`c` 無效
  3. 非等值操作不可用:`!=`、`<>`、`NOT IN`、`NOT EXISTS` → 全表掃描
  4. 範圍列右側列全部失效:`INDEX(a,b,c)`,`WHERE a=1 AND b>10 AND c=2` → `a`、`b` 走索引,`c` **完全失效**

四、 Hash 索引特點與避坑

  • 僅支援精確等值查找 (`=`、`IN`、`<=>`)
  • 存儲引擎對所有索引列計算 Hash 碼,存儲 Hash 碼 + 行指針
  • 查詢兩步:計算 Hash → 定位桶 → 遍歷桶內行比對 → 回表取數據
  • 嚴禁在低選擇性列建 Hash 索引 (如 `sex`、`status`),嚴重衝突退化為全表掃描
  • 適合高選擇性列:`user_id`、`phone`、`email`、`session_id`

五、 為什麼需要索引?三大核心收益

  1. 劇減掃描行數:索引體積 ≪ 數據體積,從 O(N) 降為 O(log N)
  2. 避免排序臨時表:索引天然有序,`ORDER BY`/`GROUP BY` 直接走索引
  3. 隨機 IO 變順序 IO:範圍掃描葉子節點鏈表,磁盤順序讀取,吞吐量提升數量級

六、 索引越多越好?三大代價

  1. 寫入放大:每次 INSERT/UPDATE/DELETE 需同步維護所有索引
  2. 優化器選擇困難:索引過多導致統計信息收集慢、執行計劃評估時間長
  3. 空間佔用:每個非聚簇索引葉子節點存主鍵值,體積可觀

七、 索引建立三大策略 (生產環境鐵律)

  1. 索引列不可使用表達式/函數
    -- ❌ 失效
    WHERE TO_DAYS(out_date) - TO_DAYS(NOW()) <= 30
    -- ✅ 改寫
    WHERE out_date < DATE_ADD(NOW(), INTERVAL 30 DAY)
  2. 索引長度控制:InnoDB 單列 ≤ 767 字節 (utf8mb4 255 字符),組合索引總長 ≤ 3072 字節。超長列用前綴索引 `INDEX(name(20))`
  3. 前綴區分度驗證:
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved