MySQL 官方定義:索引是幫助 MySQL 高效獲取數據的數據結構。本質上是為了繞過順序掃描 O(n),通過 B+Tree 實現 O(log n) 查找。
| 特性 | MyISAM | InnoDB |
|---|---|---|
| 數據存儲 | 堆表 + 索引指向地址 | 索引組織表(聚簇) |
| 主索引葉子 | 行地址 | 完整行數據 |
| 輔助索引葉子 | 行地址 | 主鍵值 |
| 回表開銷 | 一次定位 | 兩次 B+Tree 查找 |
| 主鍵設計影響 | 無特別要求 | 直接決定聚簇索引結構 |
-- 理想情況:頁填滿 → 分配新頁 → 續寫 -- 無數據移動、無碎片、無額外 I/O
-- 隨機位置插入 → 頁移動、分裂、碎片 -- 目標頁可能已刷盤 → 讀回 → 修改 → 刷盤 -- 導致寫放大、空間浪費、OPTIMIZE TABLE 維護
INDEX idx_a_b_c (a, b, c) WHERE a=1 -- ✅ 用到 a WHERE a=1 AND b=2 -- ✅ 用到 a,b WHERE a=1 AND c=3 -- ⚠️ 只用到 a WHERE b=2 -- ❌ 無法使用
WHERE a=1 AND b>2 AND c=3 -- 只用到 a,b(b 是範圍)
INDEX idx_a_b (a, b) SELECT a, b FROM t WHERE a=1; -- Extra: Using index,只掃描索引
-- 原 VARCHAR(100) 索引大 -- 分析選擇性 SELECT COUNT(DISTINCT LEFT(email, 10))/COUNT(*) FROM users; -- 0.92 -- 創建前綴索引 ALTER TABLE users ADD INDEX idx_email_prefix (email(10));
缺點:不可用於 ORDER BY/GROUP BY/覆蓋索引
WHERE 條件下推到存儲引擎過濾,減少回表。EXPLAIN 顯示 Using index condition。
INDEX idx_a_b (a, b) ORDER BY a, b -- ✅ 索引順序直接返回 ORDER BY a DESC, b -- ⚠️ 8.0+ 支持降序索引 ORDER BY b, a -- ❌ 需 filesort
-- titles 表主鍵 (emp_no, title, from_date)
EXPLAIN SELECT * FROM titles
WHERE emp_no=10001 AND title='Senior Engineer' AND from_date='1986-06-26';
-- type=const, key=PRIMARY, key_len=59 (全鍵匹配)
EXPLAIN SELECT * FROM titles WHERE emp_no=10001;
-- type=ref, key=PRIMARY, key_len=4 (只用 emp_no)
EXPLAIN SELECT * FROM titles WHERE emp_no=10001 AND from_date='1986-06-26';
-- type=ref, key=PRIMARY, key_len=4 (title 缺失,from_date 無法用到)
-- 填坑優化:title 值少用 IN 列舉
EXPLAIN SELECT * FROM titles
WHERE emp_no=10001
AND title IN ('Senior Engineer','Staff',...)
AND from_date='1986-06-26';
-- type=range, key_len=59 (全鍵用上)
Selectivity = COUNT(DISTINCT col) / COUNT(*) -- 選擇性接近 1:優秀(如主鍵、唯一鍵) -- 選擇性 < 0.01:極差(如性別、狀態),建索引收益低