不是必须,但最直接安全的方式是用 DISTINCT;它对整行去重,不改结构、不依赖索引;无法按某列去重取完整记录时需用窗口函数或关联子查询。

MySQL 查询去重必须用 DISTINCT 吗?
不是必须,但最直接、最安全的方式就是用 DISTINCT。它作用在 SELECT 阶段,对结果集的行做唯一性判断,不改表结构、不依赖索引,适合绝大多数“查出来别重复”的场景。
常见错误现象:只加 GROUP BY 却没写聚合函数,或误以为 ORDER BY 能去重 —— 这些都不行,ORDER BY 只排序,GROUP BY 若无 SELECT 中的字段对应或聚合,会报错或行为不可控。
-
DISTINCT必须放在SELECT后第一个位置,比如SELECT DISTINCT name, city FROM users - 它对整行生效:只要所有选中的列组合值完全相同,才视为重复;哪怕只有一列不同,就算不同行
- 不能对部分列去重再取其他列(比如“按
email去重,但要拿到最新一条的id”),这时DISTINCT无能为力,得换思路
为什么 DISTINCT 有时不生效?
表面写了 DISTINCT 却还是看到重复,大概率是字段里混了不可见字符,或者类型隐式转换导致“看起来一样,实际不同”。比如 VARCHAR 字段末尾空格在某些校对规则下会被忽略,但 DISTINCT 仍按字节比对;又比如把数字和字符串混着查:SELECT DISTINCT 1, '1',它们类型不同,不会被当作重复。
- 检查是否有隐藏字符:用
HEX(col)或LENGTH(col)看长度是否异常 - 确认字段校对规则(
COLLATION),尤其是_ci(大小写不敏感)和_bin(二进制)差异会影响比较逻辑 - 避免在
DISTINCT中混用表达式和原始字段,例如SELECT DISTINCT name, UPPER(name)—— 这会让去重逻辑变复杂且难预期
DISTINCT 和 GROUP BY 哪个更快?
大多数情况下,DISTINCT 更轻量。MySQL 会对 DISTINCT 做内部优化,比如利用索引跳过重复扫描;而 GROUP BY 默认会强制排序(除非显式加 ORDER BY NULL),额外消耗 CPU 和临时空间。
- 如果只是去重,别写
GROUP BY+MIN(id)这类“顺手加聚合”的操作 —— 这属于功能错配,性能更差 - 有索引覆盖时,
DISTINCT可能走索引直接去重,GROUP BY却可能触发Using temporary; Using filesort - 注意:5.7+ 版本中,
DISTINCT和GROUP BY的执行计划越来越接近,但语义和可读性上,该用哪个还是得看目的
想按某字段去重但保留完整记录,DISTINCT 不够用怎么办?
DISTINCT 只能返回去重后的“一行”,没法指定留哪一条(比如“每个 email 只留 created_at 最大的那条”)。这时候得用窗口函数或关联子查询。
- MySQL 8.0+ 推荐用
ROW_NUMBER() OVER (PARTITION BY email ORDER BY created_at DESC),然后外层筛rn = 1 - 低版本可用自连接或左连接:比如
SELECT a.* FROM users a LEFT JOIN users b ON a.email = b.email AND a.created_at - 别用
GROUP BY email配SELECT *—— 这是非法 SQL(SQL92 标准不允许多值字段未聚合),MySQL 5.7 strict 模式下直接报错:ERROR 1055
真正麻烦的从来不是怎么写去重,而是想清楚“重复”的定义到底是什么:是整行相同?某个业务主键相同?还是逻辑上应合并的多条记录?这一步没理清,后面所有写法都是白搭。










