-- 全行去重
SELECT DISTINCT * FROM table_name;
-- 指定列去重
SELECT DISTINCT col1, col2 FROM table_name;
-- 統計去重數量
SELECT COUNT(DISTINCT col) FROM table_name;
MySQL 內部將 DISTINCT 轉換為 GROUP BY 所有選中列 執行。兩種實現路徑:
Using index for group-by(鬆散索引掃描)或 Using index(緊湊索引掃描)Using temporary,不再額外 filesort(DISTINCT 不保證輸出順序)SELECT DISTINCT *EXISTS / IN 子查詢語義化表達「存在性」,避免 JOIN 膨脹SELECT DISTINCT col FROM t ORDER BY col → 臨時表去重後再排序 → Using temporary; Using filesortSELECT DISTINCT col FROM (SELECT col FROM t WHERE ...) 讓過濾先於去重GROUP BY col 可直接複用去重中間結果| 場景 | DISTINCT 耗時 | GROUP BY 耗時 | 結論 |
|---|---|---|---|
| 無索引 | ~73 ms | ~73 ms | 基本持平,DISTINCT 略快 |
| 有索引 | ~2.4 ms | ~1.2 ms | GROUP 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;
理解原理、看執行計劃、按索引設計,去重查詢才能又對又快。