distinct作用于整行而非单列,即使只选一列,若该列在不同行中对应其他隐含字段(如join引入的列)值不同,仍视为不同行;误加多余列或null合并也会导致结果偏少。

DISTINCT 对单列去重时,为什么有时结果比预期少?
因为 DISTINCT 作用于整行(即使只写一列),它会先按 SELECT 后所有字段组合去重,再投影出指定列。如果想只看某列唯一值,但该列在不同行中对应其他列值不同,DISTINCT 仍会保留多条——因为它看到的是“整行不同”。
实操建议:
- 确认是否真需要“仅该列逻辑唯一”,如果是,且不关心其他字段,直接
SELECT DISTINCT column_name FROM table即可 - 若发现结果偏少,检查是否误写了多余列在 SELECT 中(比如
SELECT DISTINCT a, b FROM t实际是按 (a,b) 去重) - 注意 NULL 被视为相同值:同一列多个 NULL 会被
DISTINCT合并为一个
用 DISTINCT 对多列去重,等价于 GROUP BY 吗?
语义上接近,但行为和性能有差异。DISTINCT (a, b) 和 GROUP BY a, b 在无聚合函数时结果一致,但数据库优化器处理方式不同。
实操建议:
- 优先用
DISTINCT a, b,语法更直白,意图明确 - 不要在
DISTINCT后加聚合函数(如COUNT(DISTINCT a)是合法的,但SELECT DISTINCT a, COUNT(*)会报错) - 多列
DISTINCT可能触发临时表或排序,尤其在无联合索引时;若列数多、数据量大,考虑给(a, b, ...)建联合索引加速 - MySQL 8.0+ 和 PostgreSQL 支持
DISTINCT ON (a)(PostgreSQL 特有),可按首列去重并保留每组第一条,DISTINCT本身不支持该语义
DISTINCT 性能差,有没有替代方案?
当表很大、去重字段无索引、或需频繁执行时,DISTINCT 往往成为瓶颈——它通常依赖排序或哈希去重,内存/磁盘开销高。
实操建议:
- 先查执行计划:
EXPLAIN SELECT DISTINCT a FROM t,看是否用了 filesort 或 temporary - 为去重字段建索引:单列去重建单列索引,多列去重建联合索引(顺序按 SELECT 中列序)
- 若只需计数,用
COUNT(DISTINCT a)比先SELECT DISTINCT a再 COUNT 更快(引擎可优化) - 极端场景(如日志表实时去重),改用物化视图、定期汇总表,或应用层用布隆过滤器预筛
ORDER BY 和 DISTINCT 能一起用吗?
可以,但有严格限制:ORDER BY 的字段必须出现在 SELECT 列表中(SQL 标准要求),且不能是表达式或别名(除非数据库明确支持,如 PostgreSQL 允许别名)。
实操建议:
- 写法必须是:
SELECT DISTINCT a FROM t ORDER BY a,而不是SELECT DISTINCT a FROM t ORDER BY b - 如果想按某列排序但不去重它,得用子查询或 CTE,例如:
SELECT a FROM (SELECT DISTINCT a, b FROM t) AS tmp ORDER BY b LIMIT 10
- MySQL 5.7 默认开启
ONLY_FULL_GROUP_BY,会连带影响 DISTINCT + ORDER BY 的合法性判断,注意检查 SQL mode










