distinct按select字段组合去重,非单列去重;混入col2时去重依据是(col1,col2)组合,故行数≠col1唯一值个数;null视为相同值,只保留一个。

DISTINCT 只作用于 SELECT 后面的字段组合,不是“去重整行”而是“去重字段值组合”
为什么 SELECT DISTINCT col1 返回的行数 ≠ 表中 col1 的实际唯一值个数?
常见错误是以为 DISTINCT 会先提取所有 col1 值再去重,实际上它是在最终结果集上按所选字段做唯一性判断。如果查询中混入了非聚合、非分组的其他字段(比如 SELECT DISTINCT col1, col2 FROM t),那去重依据就是 (col1, col2) 这一对值——哪怕 col1 相同但 col2 不同,也会被当作两行保留。
- 正确理解:
DISTINCT不是预处理步骤,它不改变数据源,只过滤输出结果 - 典型陷阱:在含
JOIN或子查询的语句里加DISTINCT,可能掩盖关联爆炸导致的重复,但无法替代正确的GROUP BY或EXISTS逻辑 - 性能提示:MySQL 对
DISTINCT通常会隐式添加临时表 + 排序,大数据量时比等价的GROUP BY略慢(尤其无索引字段)
DISTINCT 和 GROUP BY 在语义与行为上的关键差异
两者都可实现去重,但底层机制和约束完全不同。用错容易报错或结果异常。
-
DISTINCT允许 SELECT 后跟任意表达式(如UPPER(name)),但不能带聚合函数(COUNT()、MAX()等)——否则会报错Invalid use of group function -
GROUP BY要求所有非聚合字段必须出现在GROUP BY子句中;而DISTINCT没这个限制,写起来更自由,但也更容易写出逻辑模糊的语句 - MySQL 5.7+ 严格模式下,
SELECT DISTINCT a, b FROM t和SELECT a, b FROM t GROUP BY a, b结果一致;但若写成SELECT DISTINCT a, b, c FROM t,就无法用GROUP BY a替代——因为b和c没参与分组,值不确定
什么时候该用 DISTINCT,什么时候该换思路?
单纯去重只是表象,真正要解决的常是业务逻辑问题:你要的是“任一匹配项”,还是“所有匹配项中的代表”?
- 查用户所在城市列表:
SELECT DISTINCT city FROM users✅ 合理,目标就是枚举唯一值 - 查每个城市的最新订单 ID:
SELECT DISTINCT city, order_id FROM orders ORDER BY created_at DESC❌ 错误——ORDER BY在DISTINCT之后执行,无法保证取到“最新”的order_id;应改用窗口函数或相关子查询 - 联表后去重却漏数据:比如
SELECT DISTINCT u.id, u.name FROM users u JOIN orders o ON u.id = o.user_id,如果某用户有 5 笔订单,这条语句仍只返回 1 行;但若想“只要有过订单的用户”,其实更清晰的写法是SELECT id, name FROM users WHERE EXISTS (SELECT 1 FROM orders WHERE user_id = users.id)
最易被忽略的一点:DISTINCT 对 NULL 的处理是标准的——所有 NULL 被视为相同值。所以 SELECT DISTINCT col FROM t 中,无论有多少个 NULL,结果最多只出现一个 NULL。这点在统计类查询中如果不提前意识到,可能导致计数偏差。











