GROUP BY 本質上是「排序 + 分組 + 聚合」。MySQL 優化器根據索引可用性,會選擇三種實現方式:鬆散索引掃描、緊湊索引掃描、臨時表 + Filesort。理解其觸發條件與效能差異,是編寫高效聚合查詢的關鍵。
GROUP BY 欄位為同一複合索引的最左連續前綴(如 INDEX (a,b,c),GROUP BY a,b 可,GROUP BY a,c 不可)。WHERE a=1 AND b=2)。DISTINCT、無 HAVING、無 ORDER BY(除非與 GROUP BY 順序一致)。Extra: Using index for group-by
O(分組數) 而非 O(總行數)。GROUP BY 欄位在索引中但非最左前綴,或有範圍條件導致無法跳躍。INDEX (a,b,c),WHERE a=1 GROUP BY b(a 為常數填補缺口,形成前綴)。Extra: Using where; Using index -- 無 "for group-by"
COUNT、SUM、AVG 等)。GROUP BY 與 ORDER BY 欄位不一致且無索引支援。Extra: Using temporary; Using filesort
| 場景 | 優化手段 | 預期效果 |
|---|---|---|
| GROUP BY a,b + MAX(c) | 建立 INDEX (a,b,c) | 鬆散掃描,極速 |
| WHERE a=1 GROUP BY b | 建立 INDEX (a,b) | 緊湊掃描,避免排序 |
| GROUP BY c (無索引) | 建立 INDEX (c) 或覆蓋索引 | 緊湊掃描或鬆散掃描 |
| 大表 COUNT/SUM | 預聚合表、物化視圖、ClickHouse 等 OLAP 引擎 | 避免臨時表 |
| GROUP BY 與 ORDER BY 不同 | 調整索引順序匹配 ORDER BY,或接受 Filesort | 減少排序開銷 |
WHERE a=5 GROUP BY b 可用 INDEX (a,b) 實現緊湊掃描;WHERE a IN (1,2) GROUP BY b 則不行(非常數)。SELECT SQL_SMALL_RESULT ... GROUP BY 告知優化器結果集小,傾向記憶體臨時表。Created_tmp_tables、Created_tmp_disk_tables、Sort_merge_passes 暴增即為 GROUP BY 瓶頸信號。