Loose Index Scan(鬆散索引掃描) 是 MySQL 5.0+ 引入的 GROUP BY 極致優化策略,透過索引樹「跳躍式」讀取,僅訪問每個分組的第一筆記錄,將掃描成本從 O(N) 降為 O(分組數)。本文深度剖析其觸發條件、執行原理、EXPLAIN 特徵與實戰邊界。
當 MySQL 完全利用有序索引(B-Tree)實現 GROUP BY 時,不需要掃描所有滿足條件的索引鍵,即可完成分組聚合並得出結果。因為僅讀取索引鍵的「一部分」(最左前綴),故稱「鬆散」。
(a,b) 查詢 WHERE b BETWEEN ... 必須全表掃描MIN()/MAX() 聚合(c1,c2,c3) → 支援 GROUP BY c1、GROUP BY c1,c2 → 不支援 GROUP BY c1,c3、GROUP BY c2(c1,c2,c3),查詢 GROUP BY c1,c2 → WHERE c3 = 5 合法,WHERE c3 > 5 非法type: range / ref / index key: 使用的索引名 Extra: Using index for group-by
-- 1. 基礎分組 SELECT c1, c2 FROM t1 GROUP BY c1, c2; SELECT DISTINCT c1, c2 FROM t1; -- DISTINCT 等價 GROUP BY -- 2. MIN/MAX 聚合 SELECT c1, MIN(c2) FROM t1 GROUP BY c1; SELECT MAX(c3), MIN(c3), c1, c2 FROM t1 WHERE c2 > 100 GROUP BY c1, c2; -- 3. WHERE 常數填補 SELECT c1, c2 FROM t1 WHERE c1 < 100 GROUP BY c1, c2; SELECT c1, c2 FROM t1 WHERE c3 = 'const' GROUP BY c1, c2;
| SQL 模式 | 失效原因 | 改寫方向 |
|---|---|---|
SELECT c1, SUM(c2) FROM t1 GROUP BY c1 | 聚合非 MIN/MAX | 改用緊湊掃描或臨時表 |
SELECT c1,c2 FROM t1 GROUP BY c2, c3 | GROUP BY 非索引最左 | 調整索引順序或 SQL 順序 |
SELECT c1,c3 FROM t1 GROUP BY c1, c2 | SELECT 引用非 GROUP BY 索引欄位且無常數條件 | 加 WHERE c3 = const |
SELECT c1,c3 FROM t1 WHERE c3 = 'a' GROUP BY c1, c2 | SELECT 引用 c3 但 GROUP BY 無 c3(MySQL 5.6- 限制) | 升級 5.7+ 或移除 c3 |
無 WHERE 子句(全索引掃描):
讀取鍵值數 = 分組數 ≪ 總行數。例如 1 億行、1 萬組 → 僅讀 1 萬鍵值,理論加速 10,000 倍。
有 WHERE 範圍/等值條件:
對每個滿足範圍的分組,定位第一鍵 → 讀取 → 跳躍下一組。讀取鍵值數 ≈ 分組數 × 平均每組首鍵定位成本。
WHERE 常數等值欄位 + GROUP BY 欄位 + MIN/MAX 聚合欄位MIN/MAX 替代 SUM/COUNT 就替代(如求最新/最早記錄)EXPLAIN 必見 Using index for group-byHandler_read_key / Handler_read_next 比值極低表示鬆散掃描生效鬆散索引掃描是 MySQL GROUP BY 優化的「皇冠上的明珠」,掌握其嚴格邊界,將分組查詢從秒級降為毫秒級,是索引設計與 SQL 改寫的最高投資報酬比動作。