本文承接上篇,使用 MySQL 官方 employees 示例庫(44 萬+ 行),通過實際 EXPLAIN 執行計劃,深度講解 **聯合索引最左前綴原理**、**EXPLAIN 關鍵列解讀**、**索引選擇性與前綴索引**、**InnoDB 主鍵選擇對插入性能的決定性影響**。
實驗表 employees.titles,主鍵 PRIMARY KEY (emp_no, title, from_date)。刪除輔助索引後,僅保留主鍵進行純淨分析。
| 場景 | SQL 片段 | Key_len | Type | 索引使用 | 核心結論 |
|---|---|---|---|---|---|
| 1. 全列精確匹配 | WHERE emp_no=... AND title=... AND from_date=... | 59 | const | ✅ 全用 | 順序無關,優化器自動調整 |
| 2. 最左前綴匹配 | WHERE emp_no=... | 4 | ref | ✅ 僅第一列 | key_len=4 對應 emp_no(int) |
| 3. 中間列缺失 | WHERE emp_no=... AND from_date=... | 4 | ref | ⚠️ 僅第一列 | title 缺失斷開前綴,from_date 退化為 WHERE 過濾 |
| 4. 無第一列 | WHERE from_date=... | NULL | ALL | ❌ 全表掃描 | 非最左前綴,索引失效 |
| 5. LIKE 前綴匹配 | WHERE emp_no=... AND title LIKE 'Senior%' | 56 | range | ✅ 兩列 | % 不在開頭可用索引 |
| 6. 範圍查詢 | WHERE emp_no < ... AND title=... | 4 | range | ⚠️ 僅第一列 | 範圍列後的列無法用索引 |
| 7. 函數/表達式 | WHERE left(title,6)='Senior' | 4 | ref | ❌ 僅第一列 | 函數導致索引失效,需改用 LIKE |
場景 3 中 title 只有 7 個枚舉值,可用 IN 湊齊最左前綴:
WHERE emp_no=...
AND title IN ('Senior Engineer','Staff',...) -- 填滿 title
AND from_date=...
實測 key_len=59,**三列全用**,性能提升顯著。但枚舉值多時不適用,需建輔助索引 (emp_no, from_date)。
| 列 | 含義 | 重點關注 |
|---|---|---|
id | SELECT 序列號 | 同 id 從上往下;衍生表 <derivedN> 指向 id=N |
select_type | 查詢類型 | SIMPLE/PRIMARY/SUBQUERY/DERIVED/UNION/UNION RESULT |
type | 訪問類型(核心) | system > const > eq_ref > ref > range > index > ALL,至少達 range,最好 ref |
possible_keys | 可能用到的索引 | 為 NULL 表示無索引可用 |
key | 實際用到的索引 | 為 NULL 表示全表掃描 |
key_len | 索引長度(字節) | 推斷聯合索引用了幾列(int=4, date=3, varchar(N)=3N+2) |
ref | 與 key 配合的列/常量 | const 表示常量 |
rows | 預估掃描行數 | 越小越好,InnoDB 為估算值 |
Extra | 額外信息 | Using index(覆蓋索引)、Using where(後過濾)、Using filesort、Using temporary |
sort_buffer_size 少。sort_buffer_size 多。max_length_for_sort_data(默認 1024)與 SELECT 列總長度決定算法。選擇性 = Cardinality / 總行數,越接近 1 越好。
title 選擇性 < 0.0001 → **不建索引**。employees.employees 按名字搜索:first_name 選擇性 0.0042(太低),(first_name, last_name) 0.9313(高但長 30 字節)。first_name + last_name 前 4 字符SELECT COUNT(DISTINCT(CONCAT(first_name, LEFT(last_name, 4)))) / COUNT(*)
FROM employees.employees; -- 選擇性 0.9007,長度 18 字節
ALTER TABLE employees.employees
ADD INDEX `first_name_last_name4` (first_name, last_name(4));
**效果**:查詢耗時從 0.119s 降至 0.0009s,提速 120+ 倍。
⚠️ **前綴索引限制**:不可用於 ORDER BY、GROUP BY、Covering Index。
InnoDB **聚簇索引**:數據行物理順序 = 主鍵順序,葉子節點存全行數據。
OPTIMIZE TABLE 整理。CREATE TABLE t (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, -- 與業務無關
biz_id VARCHAR(32) NOT NULL, -- 業務唯一鍵,加 UNIQUE INDEX
...
) ENGINE=InnoDB;
索引調優是理論與實戰的雙重修煉。掌握 **B+Tree、最左前綴、選擇性、聚簇索引特性** 等核心原理,配合 EXPLAIN、SHOW PROFILE、慢查詢日誌持續觀測,方能在千變萬化的業務中游刃有餘。本文未覆蓋覆蓋索引、排序優化、Hash/全文索引等進階主題,留待後續專題展開。