兩者都能產生「不重複」結果集,但設計目的、適用場景、內部機制、擴展性截然不同。選錯不僅影響可讀性,更可能造成效能問題。
| 維度 | DISTINCT | GROUP BY |
|---|---|---|
| 設計目的 | 移除結果集重複列 | 將資料分組以便彙總計算 |
| 典型用法 | SELECT DISTINCT col FROM t | SELECT col, COUNT(*) FROM t GROUP BY col |
| 聚合函數 | 不支援 (單純去重) | 核心搭配 (SUM, AVG, COUNT...) |
| 多欄位去重 | DISTINCT col1, col2 (組合去重) | GROUP BY col1, col2 (分組鍵) |
| 結果排序 | 不保證順序 | 不保證順序 (需 ORDER BY) |
| NULL 處理 | 視為一值,保留一筆 NULL | 形成獨立群組 |
| HAVING 篩選 | 不支援 | 支援群組層級條件 |
| 執行計畫 | 通常用 Hash Aggregate / Sort Unique | Hash Aggregate / Sort Group |
因此:單純去重用 DISTINCT,語意更清晰、優化器路徑更短。
# 查詢 1: 去重 SELECT DISTINCT category FROM products; # 查詢 2: 分組 (無聚合) SELECT category FROM products GROUP BY category; # 結果: 執行時間差異 < 5%,執行計畫相同 (Using index for group-by) # 結論: 現代優化器對「無聚合的 GROUP BY」會優化為 DISTINCT 等價邏輯。
SELECT department, COUNT(*) AS emp_cnt, AVG(salary) AS avg_sal FROM employees GROUP BY department;
SELECT customer_id, SUM(amount) AS total FROM orders GROUP BY customer_id HAVING total > 10000;
SELECT region, product, SUM(sales) FROM sales_data GROUP BY ROLLUP (region, product);
# 取得所有有下單的客戶 ID SELECT DISTINCT customer_id FROM orders; # 取得不重複的標籤組合 SELECT DISTINCT tag1, tag2 FROM articles;
SELECT * FROM users WHERE id IN (SELECT DISTINCT user_id FROM logs WHERE action='login');
# 每類商品取最新一筆 SELECT DISTINCT ON (category) id, category, name, created_at FROM products ORDER BY category, created_at DESC;
MySQL 可用 ROW_NUMBER() OVER (PARTITION BY category ORDER BY created_at DESC) (8.0+) 達到同樣效果。
SELECT DISTINCT col1, col2, col3 ... 後面跟大量欄位 → 實際上是在做「全列組合去重」,非單欄位去重。SELECT col1, COUNT(*) FROM t GROUP BY col1 卻在 SELECT 加入未分組的 col2 → ONLY_FULL_GROUP_BY 模式報錯。DISTINCT 比 GROUP BY 慢 → 現代優化器幾乎等價,關鍵在語意正確性。掌握語意差異,寫出「對的 SQL」比寫「快的 SQL」更重要;語意正確,優化器自然幫你跑得快。