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

MySQL去重利器:DISTINCT 與 GROUP BY 異同與選型指南

     編輯:MySQL 綜合教學

MySQL去重利器:DISTINCT 與 GROUP BY 異同與選型指南

數據去重是查詢中高頻需求。MySQL提供DISTINCT和GROUP BY兩種機制,二者在功能、性能、結果集形態上存在本質差異。本文深度對比並給出選型建議。

一、DISTINCT 關鍵字

1. 語法與行為

SELECT DISTINCT column_name FROM table_name;
SELECT DISTINCT column1, column2 FROM table_name; -- 多列組合去重
  • 針對SELECT列表中所有列的組合去重
  • 僅返回去重後的列,**不返回其他列**
  • 可用於單列或多列組合

2. 示例

表user數據:

uid | username
1   | 小李
2   | 小張
3   | 小李
4   | 小王
5   | 小李
6   | 小張
SELECT DISTINCT username FROM user;
-- 結果:
username
小李
小張
小王

局限:無法同時返回uid等其他列。若強行SELECT DISTINCT username, uid,則按組合去重,username去重失效。

二、GROUP BY 分組去重

1. 語法與MySQL擴展行為

SELECT column_list FROM table_name GROUP BY column1, column2, ...;

標準SQL要求:SELECT列表僅能包含聚合函數或GROUP BY中的列。

MySQL擴展(默認ONLY_FULL_GROUP_BY關閉時):

  • 允許SELECT列表包含未分組、未聚合的列
  • 返回每組的第一行(非確定性,除非配合ORDER BY)
  • 隱含列功能:聚合函數可引用未出現在GROUP BY中的列

2. 示例

SELECT * FROM user GROUP BY username;
-- 結果(取每組第一行):
uid | username
1   | 小李
2   | 小張
4   | 小王

完美解決「去重並保留完整行」需求!

3. 多列分組

SELECT * FROM user GROUP BY username, uid;
-- 等同於無分組,因為uid唯一,返回所有行

三、核心差異對比

維度DISTINCTGROUP BY
返回列僅去重列可返回任意列(MySQL擴展)
去重粒度SELECT列表整體組合GROUP BY指定列組合
結果行數去重後唯一組合數分組數
可配合聚合不可直接聚合原生支持COUNT/SUM/AVG等
排序控制需外層ORDER BY可內部ORDER BY控制取哪行
標準兼容性標準SQLMySQL擴展(開啟ONLY_FULL_GROUP_BY受限)
性能特點內部常轉換為GROUP BY執行可利用索引分組,支持聚合下推

四、進階技巧:GROUP BY + ORDER BY 精確控制

利用MySQL擴展,在分組內排序後取第一行:

-- 取每個用戶最新的一條訂單
SELECT * FROM (
    SELECT * FROM orders ORDER BY user_id, created_at DESC
) t GROUP BY user_id;

-- 或 MySQL 8.0+ 窗口函數(標準、確定)
SELECT * FROM (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) rn
    FROM orders
) t WHERE rn = 1;

五、性能與優化建議

  1. 首選GROUP BY:功能更強、可返回完整行、支持聚合、優化器成熟
  2. 加索引:為GROUP BY列建立索引,避免臨時表+文件排序
  3. 避免SELECT *:僅選取必要列,減少臨時表大小
  4. 大數據量分頁去重:先在覆蓋索引上分組取ID,再回表
  5. 開啟ONLY_FULL_GROUP_BY:生產環境建議開啟(sql_mode),強制編寫標準兼容SQL,避免非確定性結果

六、實戰選型決策樹

需要去重?
├─ 僅需去重列本身,無聚合需求 → DISTINCT (簡潔、標準)
└─ 需保留其他列 / 需聚合統計 / 需控制取哪行 → GROUP BY
    ├─ MySQL 8.0+ → 窗口函數 ROW_NUMBER() (最標準、確定)
    ├─ 老版本 + 非嚴格模式 → GROUP BY + 子查詢ORDER BY (常用技巧)
    └─ 嚴格模式(ONLY_FULL_GROUP_BY) → 聚合函數(ANY_VALUE/MAX) 或 子查詢JOIN

七、總結

  • DISTINCT是輕量級去重工具,適用於簡單場景
  • GROUP BY是強大的分組聚合引擎,MySQL擴展使其成為「保留完整行去重」的首選
  • 理解底層機制(臨時表、文件排序、索引下推),根據數據量、版本、SQL模式選型
  • 現代應用推薦MySQL 8.0 + 窗口函數,標準、高效、可維護
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved