首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 索引深度解析:B+樹原理、單列/複合/全文索引選擇、EXPLAIN 執行計劃優化實戰

     編輯:MySQL 資料庫相關知識

索引底層:B+ 樹為什麼快

  • **有序性**:葉子節點鏈表掃描範圍查詢極快
  • **高扇出**:非葉節點只存鍵值+指針,單節點容納更多鍵,樹高通常 2-3 層
  • **覆蓋索引**:葉子節點直接存數據 (聚簇索引) 或主鍵值 (二級索引),避免回表
  • **對比**:無索引全表掃描 O(N);B+ 樹查找 O(log N),100 萬行約 20 次 I/O vs 100 萬次

索引類型全景

類型關鍵字約束適用場景創建語法
普通索引INDEX / KEY無一般查詢加速CREATE INDEX idx_name ON t(col)
唯一索引UNIQUE值唯一 (允許多 NULL)業務鍵 (email、手機號)CREATE UNIQUE INDEX uk_email ON t(email)
主鍵PRIMARY KEY唯一 + NOT NULL、聚簇索引表標識、InnoDB 必須有PRIMARY KEY (id)
全文索引FULLTEXT支援自然語言/布爾模式搜索長文本搜索、日誌分析CREATE FULLTEXT INDEX ft_content ON t(content)
空間索引SPATIALGIS 幾何類型地理位置查詢CREATE SPATIAL INDEX sp_geo ON t(geo)

單列 vs 複合索引:最左前綴原理

場景:查詢 WHERE firstname='Mike' AND lastname='Sullivan' AND age=17

  • 三個單列索引:優化器只能選一個 (如 firstname),掃描所有 Mike 再回表過濾 lastname/age,**效率低**
  • 複合索引 (firstname, lastname, age):B+ 樹按三列排序,**一次定位精確匹配行,零回表 (覆蓋索引)**,**效率最高**

最左前綴匹配規則

複合索引 (a, b, c) 可滿足:

  • WHERE a=1 AND b=2 AND c=3 ✅
  • WHERE a=1 AND b=2 ✅
  • WHERE a=1 ✅
  • WHERE b=2 ❌ (未用最左列 a)
  • WHERE a=1 AND c=3 ⚠️ (用 a,c 無法用索引查找,僅過濾)
  • ORDER BY a, b, c ✅ (避免 filesort)

索引選擇實戰:WHERE/JOIN/ORDER BY 三維分析

SELECT p.age, t.name
FROM people p
LEFT JOIN town t ON p.townid = t.townid
WHERE p.firstname='Mike' AND p.lastname='Sullivan';

**必建索引**:

  1. people(firstname, lastname) — WHERE 等值條件
  2. town(townid) — JOIN 關聯列 (被驅動表)
  3. people(townid) — 可選,若 town 很大且作驅動表

**無需索引**:SELECT 列 (age, name) — 僅輸出,不參與過濾/連接/排序。

操作符與索引兼容性

操作符能否用索引條件
=, <, >, <=, >=, BETWEEN, IN✅常數在右側、列無運算
LIKE 'prefix%'✅固定前綴,非通配符開頭
LIKE '%suffix'❌導掃,除非反向索引/全文
IS NULL / IS NOT NULL✅5.6+ 優化器可用
!=, <>, NOT IN❌範圍過大,通常全掃
col + 1 = 2 / UPPER(col) = 'A'❌列上有運算/函數,索引失效 (8.0 函數索引除外)

EXPLAIN 實戰解讀

EXPLAIN SELECT peopleid FROM people 
WHERE firstname='Mike' AND lastname='Sullivan' AND age=17;
輸出關鍵列**:

列含義優秀值
type連接類型system/const/eq_ref/ref/range > index > ALL
possible_keys可能用到的索引含目標索引名
key實際用到的索引非 NULL,名稱明確
key_len索引使用長度 (字節)與預期列長度匹配
ref比較值來源const/列名
rows預估掃描行數接近 1 (唯一) 或小數值
Extra額外信息Using index (覆蓋) 好;Using filesort/Using temporary 差

索引代價:寫入放大與空間佔用

  • 空間**:每個索引 ≈ 0.1-0.3x 數據大小,過多索引超文件系統/InnoDB 限制
  • 寫入**:INSERT/UPDATE/DELETE 需同步維護所有索引,**索引越多寫入越慢**
  • 鎖競爭**:二級索引鎖 + 聚簇索引鎖,高併發下熱點索引成瓶頸
  • 統計失真**:大量刪除/更新導致 Cardinality 不準,優化器誤判,**定期 ANALYZE TABLE**

優化檢查清單

  1. 慢查詢日誌 + pt-query-digest 找出 Top SQL
  2. EXPLAIN 觀察 type/key/rows/Extra
  3. 缺索引 → 加複合索引 (最左前綴、覆蓋)
  4. 索引未用 → 檢查操作符/函數/隱式轉換/統計信息
  5. 寫入熱點 → 評估索引必要性、拆分熱表、分區/分表
  6. 定期 ANALYZE TABLE、監控 Innodb_buffer_pool_reads、Handler_read_rnd_next

結語

索引是關係型數據庫**性能杠杆**,但**不是銀彈**。**B+ 樹有序結構 + 最左前綴 + 覆蓋索引 + EXPLAIN 驗證** 是核心方法論。記住:**為查詢建索引,為寫入減索引,為業務找平衡**。大表索引變更必走 gh-ost/pt-online-schema-change 在線無鎖變更,嚴禁直接 ALTER TABLE 鎖表數小時。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved