distinct是专为去重设计的语义操作,group by本质用于分组聚合;仅需去重时,distinct逻辑更轻、优化路径更直接,无索引时group by可能多触发using filesort。

GROUP BY 必须配合聚合函数,否则行为不可靠
MySQL 在 only_full_group_by 模式下(默认开启),SELECT 中所有非分组字段都必须出现在 GROUP BY 子句里,或被包裹在聚合函数中。否则会直接报错:Expression #2 of SELECT list is not in GROUP BY clause。
如果关闭该模式,MySQL 会从每组中随机选一行的值返回——比如 SELECT user_id, amount FROM orders GROUP BY user_id,amount 的值可能来自任意一笔订单,完全不可控。财务、对账类场景中这极易引发数据错误。
- 想保留某组中最新的一条?得用
MAX(created_at)+ 子查询或窗口函数,不能靠GROUP BY“碰运气” - 想取某组中金额最大的那笔?要用
MAX(amount),不是直接写amount - 纯为了去重而写
GROUP BY,却没加任何聚合逻辑,属于误用
DISTINCT 是整行去重,不是“按某列去重”
DISTINCT 判定重复的依据是:SELECT 出来的**整行所有字段值完全相同**。它不识别“业务主键”或“逻辑唯一性”,只认字面一致。
例如表中有两行:(bill_no='B001', amount=500) 和 (bill_no='B001', amount=1000),执行 SELECT DISTINCT bill_no, amount FROM t 会返回两条——因为整行不同;而业务想要的“每个 bill_no 只出现一次”,DISTINCT 根本做不到。
- 单列去重:
SELECT DISTINCT bill_no FROM t✅ - 多列联合去重:
SELECT DISTINCT bill_no, status FROM t✅(只要这两列组合值重复才去) - “按
bill_no去重,但还要带出amount” ❌ —— 这不是DISTINCT的能力范围
性能差异取决于场景和索引,不能一概而论
有索引时,DISTINCT 和 GROUP BY 都可能走索引扫描,性能接近;没索引时,两者都会触发临时表 + 排序,但行为不同:
-
DISTINCT通常做一次全量去重(哈希 or 排序),目标是“输出唯一行” -
GROUP BY默认会隐式排序(MySQL 8.0 前),即使你没写ORDER BY,也可能触发filesort,拖慢查询 - 大数据量(如千万级)且仅需去重时,
DISTINCT更轻量;若后续要统计每组数量,GROUP BY一步到位,比DISTINCT套子查询更高效
注意:COUNT(DISTINCT column) 是合法聚合,但 SELECT DISTINCT COUNT(...) 是语法错误。
别混淆“能实现同样结果”和“设计目的相同”
像 SELECT DISTINCT a FROM t 和 SELECT a FROM t GROUP BY a 看似等价,但本质不同:前者是去重操作,后者是分组操作。这种等价只在单列、无其他字段、不关心顺序时成立。
一旦加了条件或扩展需求,裂痕立刻暴露:
- 要查“每个
a对应的最大b”?只能用GROUP BY a+MAX(b) - 要查“去重后的
a总共有多少种”?SELECT COUNT(DISTINCT a) FROM t最直接 - 要查“哪些
a出现了超过 3 次”?必须用GROUP BY a HAVING COUNT(*) > 3
真正容易被忽略的点是:业务说的“去重”,常常隐含“按某字段归并 + 取代表性值”的语义,而 DISTINCT 和裸 GROUP BY 都无法安全满足——这时候该考虑 ROW_NUMBER() 或关联子查询。











