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

MySQL 單列索引 vs 組合索引:原理深度解析與最左前綴實戰指南

     編輯:MySQL 資料庫相關知識

核心概念對比

維度單列索引組合索引 (聯合索引)
定義單個列上建立的索引多個列組合建立的單個索引,鍵值為列值拼接
結構B+樹,葉子節點存 (列值, 主鍵/RowID)B+樹,葉子節點存 (列1值, 列2值..., 主鍵/RowID),按定義順序排序
查詢匹配精確匹配該列遵循最左前綴原則,從最左列開始連續匹配
維護成本低 (單列寫入更新)高 (多列寫入需更新一個索引,但比多個單列索引低)
存儲空間單列索引大小通常小於多個單列索引總和 (共享 B+樹節點)

實戰場景演示

測試表結構


CREATE TABLE myIndex (
  i_testID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  vc_Name VARCHAR(50) NOT NULL,
  vc_City VARCHAR(50) NOT NULL,
  i_Age INT NOT NULL,
  i_SchoolID INT NOT NULL
) ENGINE=InnoDB;

-- 模擬 10000 行數據,vc_Name='erquan' 有 5 行,city/age/school 組合各異

目標查詢


SELECT i_testID FROM myIndex
WHERE vc_Name='erquan' AND vc_City='鄭州' AND i_Age=25;

方案對比分析

方案 A:單列索引 (三個獨立索引)


ALTER TABLE myIndex ADD INDEX idx_name (vc_Name);
ALTER TABLE myIndex ADD INDEX idx_city (vc_City);
ALTER TABLE myIndex ADD INDEX idx_age (i_Age);

執行流程:

  1. 優化器選擇選擇性最高的單列索引 (通常是 vc_Name,過濾出 5 行)
  2. 將 5 行主鍵 ID 回表查詢完整行
  3. 在 Server 層過濾 vc_City='鄭州' 和 i_Age=25

缺點: 只能利用一個索引,其餘條件需回表後過濾,隨著數據量增長,回表開銷線性增長。

方案 B:組合索引 (最優)


ALTER TABLE myIndex ADD INDEX idx_name_city_age (vc_Name(10), vc_City, i_Age);

設計細節:

  • vc_Name(10):前綴索引,名字通常 ≤ 10 字,大幅減小索引體積、提升寫入速度、加快掃描
  • 列順序:vc_Name (高選擇性) → vc_City → i_Age,符合查詢 WHERE 順序

執行流程: 直接在 B+樹上按 (erquan, 鄭州, 25) 定位唯一葉子節點,零回表、零全掃描、毫秒級返回。

最左前綴原則深度解析

組合索引 (a, b, c) 的 B+樹排序邏輯:先按 a 排序,a 相同再按 b,以此類推。因此:

✅ 能用到索引的查詢


WHERE a = 1
WHERE a = 1 AND b = 2
WHERE a = 1 AND b = 2 AND c = 3
WHERE a = 1 AND b > 2          -- b 範圍查詢,c 失效
WHERE a = 1 AND b LIKE 'xyz%'  -- 前綴模糊匹配

❌ 無法用到索引的查詢


WHERE b = 2                    -- 缺最左列 a
WHERE c = 3                    -- 缺 a,b
WHERE b = 2 AND c = 3          -- 缺 a
WHERE a = 1 AND c = 3          -- 中間斷層,c 失效 (僅用到 a)
WHERE a > 1 AND b = 2          -- a 範圍查詢,b 失效

💡 索引下推 (ICP, 5.6+) 優化

對於 WHERE a=1 AND b LIKE 'xyz%' AND c=3,傳統需回表過濾 c,ICP 在存儲引擎層直接過濾 c,減少回表次數。

為什麼不建議「三個單列索引」代替組合索引?

  1. 優化器單選: MySQL 單表查詢只能使用一個索引 (Index Merge 除外,但效率低且不穩定)
  2. 回表放大: 單列索引命中行數 × 回表成本,組合索引直接定位
  3. 維護開銷: 3 個索引 = 3 次 B+樹插入/刪除/更新,組合索引 = 1 次
  4. 空間佔用: 3 個獨立 B+樹 > 1 個聯合 B+樹 (共享非葉子節點)

索引設計黃金法則

  1. 高選擇性列前置: 區分度 = COUNT(DISTINCT col)/COUNT(*),越接近 1 越前
  2. WHERE/ORDER BY/GROUP BY 列優先: 覆蓋查詢模式
  3. 範圍列後置: 範圍查詢 (>, <, >=, <=, LIKE '%...') 會阻斷後續列使用
  4. 前綴索引優化長字符串: VARCHAR(255) → INDEX idx_col (col(10)),驗證 SELECT COUNT(DISTINCT LEFT(col,10))/COUNT(*) FROM tbl 區分度
  5. 覆蓋索引避免回表: SELECT a,b FROM t WHERE c=1 → INDEX idx_c_ab (c,a,b)
  6. 單表索引數 ≤ 5: 過多索引拖慢寫入、佔用空間、誤導優化器

驗證與監控


-- 查看索引使用情況
SHOW INDEX FROM myIndex;
EXPLAIN SELECT ...;  -- 關注 type=ref/range, key=idx_name_city_age, rows=1

-- 監控未使用索引 (sys schema)
SELECT * FROM sys.schema_unused_indexes;

-- 監控冗余索引
SELECT * FROM sys.schema_redundant_indexes;

總結

組合索引通過「最左前綴」機制,將多維查詢條件壓縮為單一 B+樹查找路徑,是高性能查詢的核心利器。單列索引僅適用於單列高頻過濾場景。實戰中:分析慢查詢 → 提取 WHERE/JOIN/ORDER BY 列 → 按選擇性排序 → 建組合索引 → EXPLAIN 驗證 → 監控命中率,形成閉環。記住:索引是把雙刃劍,讀快寫慢,精準建立,定期清理。

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