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

MySQL DISTINCT 去重全解析:語法、性能陷阱、優化策略與 GROUP BY 對比

     編輯:MySQL 綜合教學

基本語法

-- 全行去重
SELECT DISTINCT * FROM table_name;

-- 指定列去重
SELECT DISTINCT col1, col2 FROM table_name;

-- 統計去重數量
SELECT COUNT(DISTINCT col) FROM table_name;

DISTINCT 執行原理

MySQL 內部將 DISTINCT 轉換為 GROUP BY 所有選中列 執行。兩種實現路徑:

  1. 索引掃描(最優):WHERE 條件命中索引,且索引順序滿足去重列順序 → Using index for group-by(鬆散索引掃描)或 Using index(緊湊索引掃描)
  2. 臨時表 + 排序/哈希:無合適索引 → 創建內存臨時表(超限轉磁盤 MyISAM/InnoDB),插入去重 → Using temporary,不再額外 filesort(DISTINCT 不保證輸出順序)

性能陷阱與優化

❌ 陷阱 1:濫用 SELECT DISTINCT *

  • 所有列參與去重,臨時表寬、內存壓力大
  • **修正**:僅選業務需要的列

❌ 陷阱 2:高層查詢用 DISTINCT 掩蓋 JOIN 錯誤

  • 多表 JOIN 產生笛卡爾積 → 用 DISTINCT 強行去重 → 掩蓋缺失 JOIN 條件導致的數據錯誤
  • **修正**:用 EXISTS / IN 子查詢語義化表達「存在性」,避免 JOIN 膨脹

❌ 陷阱 3:DISTINCT + ORDER BY 強制 filesort

  • SELECT DISTINCT col FROM t ORDER BY col → 臨時表去重後再排序 → Using temporary; Using filesort
  • **修正**:若業務不需排序,去掉 ORDER BY;若需排序,確保有索引支持

優化策略清單

  1. 為去重列建立索引(單列或聯合索引順序匹配 SELECT 列順序)
  2. 用 LIMIT 限制輸出行數,減少臨時表大小
  3. 子查詢下推:SELECT DISTINCT col FROM (SELECT col FROM t WHERE ...) 讓過濾先於去重
  4. 考慮 GROUP BY 替代:需聚合統計時 GROUP BY col 可直接複用去重中間結果
  5. 大表分區/分表,將去重範圍限制在單分區

DISTINCT vs GROUP BY 性能實測(10 萬行測試表)

場景DISTINCT 耗時GROUP BY 耗時結論
無索引~73 ms~73 ms基本持平,DISTINCT 略快
有索引~2.4 ms~1.2 msGROUP BY 明顯更快(優化器對 GROUP BY 索引利用更激進)

生產環境大表通常有索引 → **優先用 GROUP BY** 替代單純去重,語義更清晰、性能不劣。

多列去重的等價寫法

-- 需求:按 title 去重,保留每組第一行的 posttime
-- 寫法 1:子查詢取最小 id
SELECT title, posttime FROM table WHERE id IN (SELECT MIN(id) FROM table GROUP BY title);

-- 寫法 2:GROUP BY 多列(若需保留所有列組合)
SELECT title, posttime FROM table GROUP BY title, posttime;

-- 寫法 3:窗口函數 (MySQL 8.0+)
SELECT title, posttime FROM (
  SELECT title, posttime, ROW_NUMBER() OVER (PARTITION BY title ORDER BY id) rn
  FROM table
) t WHERE rn = 1;

總結

  • DISTINCT 本質 = GROUP BY 無聚合
  • 有索引時 GROUP BY 更快,無索引時持平
  • 避免高層 DISTINCT 掩蓋邏輯錯誤,改用 EXISTS/IN
  • 多列去重按業務語義選擇 GROUP BY / 窗口函數 / 子查詢

理解原理、看執行計劃、按索引設計,去重查詢才能又對又快。

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