DISTINCT = GROUP BY 所有選中列(無聚合函數)
兩者共用同一套分組執行邏輯,差異僅在於:
| 路徑 | 條件 | EXPLAIN Extra | 性能 |
|---|---|---|---|
| 鬆散索引掃描 | WHERE 為常量/範圍,分組列為索引最左前綴,無其他列引用 | Using index for group-by | ⭐⭐⭐⭐⭐ 最優,直接跳躍索引鍵值 |
| 緊湊索引掃描 | WHERE 為 ref/const 等值,分組列為索引前綴 | Using where; Using index | ⭐⭐⭐⭐ 掃描符合條件的索引段,利用有序性去重 |
| 臨時表 | 無合適索引、或 SELECT 列超出索引覆蓋 | Using temporary [; Using filesort] | ⭐⭐ 內存/磁盤臨時表,DISTINCT 無 filesort,GROUP BY 有 |
EXPLAIN SELECT DISTINCT group_id FROM group_message;
-- Extra: Using index for group-by ✅
EXPLAIN SELECT DISTINCT user_id FROM group_message WHERE group_id = 2;
-- Extra: Using where; Using index ✅
EXPLAIN SELECT DISTINCT user_id FROM group_message WHERE group_id > 1 AND group_id < 10;
-- Extra: Using where; Using index; Using temporary ✅ 無 filesort
EXPLAIN SELECT DISTINCT MAX(user_id) FROM group_message WHERE group_id > 1 AND group_id < 10 GROUP BY group_id;
-- Extra: Using where; Using index; Using temporary; Using filesort ❌
GROUP BY col ORDER BY NULL:禁止隱式排序,去掉 filesort(MySQL 5.7+ 默認不再隱式排序,但顯式加上更保險)| 場景 | DISTINCT | GROUP BY | 說明 |
|---|---|---|---|
| 無索引 | 73 ms | 73 ms | 持平,臨時表去重開銷主導 |
| 有索引 | 2.4 ms | 1.2 ms | GROUP BY 索引利用更充分 |
GROUP BY col(語義明確、性能最優)DISTINCT col(簡潔)GROUP BY col + 聚合函數(必然)GROUP BY col ORDER BY col 或 DISTINCT col ORDER BY col(會 filesort,確保有索引)DISTINCT 與 GROUP BY 共享分組引擎,**索引是性能關鍵**。理解三種掃描路徑、看懂 EXPLAIN Extra,才能寫出又對又快的去重/分組查詢。