缺點:臨時表佔用磁盤/內存、filesort 耗 CPU、掃描行數 = 滿足 WHERE 的所有行。
利用索引有序特性,**直接跳躍到每組的第一條記錄**,只掃描索引中極小部分頁面,避免臨時表與排序。執行計劃 Extra 顯示 Using index for group-by。
| # | 條件 | 說明 |
|---|---|---|
| 1 | 單表查詢 | 無 JOIN |
| 2 | GROUP BY 列為索引最左前綴 | 如 idx(a,b,c) → GROUP BY a / a,b / a,b,c |
| 3 | 聚合函數僅限 MIN/MAX | 且被聚合列必須在同一索引中 |
| 4 | 索引中未被 GROUP BY 引用的列必須為常量 | WHERE 子句中對該列做等值條件 |
| 5 | 不支援前綴索引 | 如 idx(name(10)) 無法觸發 |
-- 假設 t1 有索引 idx(c1,c2,c3) SELECT c1, c2 FROM t1 GROUP BY c1, c2; SELECT DISTINCT c1, c2 FROM t1; SELECT c1, MIN(c2) FROM t1 GROUP BY c1; SELECT c1, c2 FROM t1 WHERE c1 < 100 GROUP BY c1, c2; SELECT MAX(c3), MIN(c3), c1, c2 FROM t1 WHERE c2 > 100 GROUP BY c1, c2; SELECT c2 FROM t1 WHERE c1 < 100 GROUP BY c1, c2; SELECT c1, c2 FROM t1 WHERE c3 = 100 GROUP BY c1, c2; -- c3 為常量等值
-- 聚合非 MIN/MAX SELECT c1, SUM(c2) FROM t1 GROUP BY c1; -- 違反最左前綴 SELECT c1, c2 FROM t1 GROUP BY c2, c3; -- 索引中間列無常量條件 SELECT c1, c3 FROM t1 GROUP BY c1, c2; -- c2 在索引中但無 WHERE c2=const
AVG(DISTINCT), SUM(DISTINCT), COUNT(DISTINCT) -- 示例 SELECT COUNT(DISTINCT c1), SUM(DISTINCT c1) FROM t1; SELECT COUNT(DISTINCT c1, c2), COUNT(DISTINCT c2, c1) FROM t1;
t1(c1 INT, c2 INT, c3 INT, KEY idx(c1,c2,c3))EXPLAIN SELECT c1, MIN(c2) FROM t1 GROUP BY c1; 觀察 ExtraSELECT c1, SUM(c2) FROM t1 GROUP BY c1; 的 Extra(應為 Using temporary; Using filesort)Loose Index Scan 是 MySQL 針對 GROUP BY、DISTINCT、MIN/MAX 的重要優化。核心記住:**最左前綴 + MIN/MAX + 常量補全中間列**。5.7+ 版本已穩定支援,善用此特性可讓大表分組聚合提速數十倍。