首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL DISTINCT 與 GROUP BY 內部實現原理深度對比:鬆散/緊湊索引掃描、臨時表、filesort

     編輯:MySQL 綜合教學

核心關係

DISTINCT = GROUP BY 所有選中列(無聚合函數)

兩者共用同一套分組執行邏輯,差異僅在於:

  • DISTINCT:每組取第一行,**不保證輸出順序**,**不觸發 filesort**
  • GROUP BY:默認按分組列排序(隱式 ORDER BY),**觸發 filesort**(除非用索引順序)

三種分組執行路徑

路徑條件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 解讀

1. 鬆散索引掃描

EXPLAIN SELECT DISTINCT group_id FROM group_message;
-- Extra: Using index for group-by  ✅

2. 緊湊索引掃描

EXPLAIN SELECT DISTINCT user_id FROM group_message WHERE group_id = 2;
-- Extra: Using where; Using index  ✅

3. 臨時表(DISTINCT 無 filesort)

EXPLAIN SELECT DISTINCT user_id FROM group_message WHERE group_id > 1 AND group_id < 10;
-- Extra: Using where; Using index; Using temporary  ✅ 無 filesort

4. 結合 GROUP BY + 聚合函數(觸發 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 優化小技巧

  • GROUP BY col ORDER BY NULL:禁止隱式排序,去掉 filesort(MySQL 5.7+ 默認不再隱式排序,但顯式加上更保險)
  • 確保分組列有索引,且 WHERE 條件能利用索引前綴
  • 大表分區裁剪減少掃描範圍

性能對比實測(10 萬行、有/無索引)

場景DISTINCTGROUP BY說明
無索引73 ms73 ms持平,臨時表去重開銷主導
有索引2.4 ms1.2 msGROUP BY 索引利用更充分

選擇建議

  1. **單純去重、有索引** → GROUP BY col(語義明確、性能最優)
  2. **單純去重、無索引、小結果集** → DISTINCT col(簡潔)
  3. **需聚合統計** → GROUP BY col + 聚合函數(必然)
  4. **需輸出有序** → GROUP BY col ORDER BY col 或 DISTINCT col ORDER BY col(會 filesort,確保有索引)

總結

DISTINCT 與 GROUP BY 共享分組引擎,**索引是性能關鍵**。理解三種掃描路徑、看懂 EXPLAIN Extra,才能寫出又對又快的去重/分組查詢。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved