
DISTINCT 不是简单删掉重复行,而是数据库在查询执行过程中对结果集做的一次逻辑去重操作。它的行为取决于数据量、索引情况、目标字段基数以及具体数据库的优化器策略。
去重对象是整行组合值,不是单列
DISTINCT 作用于 SELECT 后面所有列构成的元组。比如 SELECT DISTINCT a, b FROM t,判断是否重复的标准是 (a,b) 这一对值是否完全相同。只要其中任一列不同,整行就不算重复。
- 想单独获取 a 的所有不同值,应写 SELECT DISTINCT a FROM t
- 如果误以为它分别对 a 和 b 去重,容易导致结果误解
- 所有 NULL 值被视作相等,多行 NULL 组合只保留一行
底层实现主要靠排序、哈希或索引
数据库不会遍历全部数据再人工比对,而是用高效结构完成去重:
- 排序方式:先按 SELECT 列排序,再顺序扫描跳过相邻重复项;适合中小数据量,但排序开销大,内存不足会落盘
- 哈希方式:构建哈希表,以 DISTINCT 列值为 key,首次出现写入,后续跳过;速度快,但吃内存;SQL Server、新版本 PostgreSQL 常默认启用
- 索引隐式去重:若 DISTINCT 列上有唯一索引(或联合索引前导列覆盖),且查询无额外非索引列或表达式,优化器可能直接扫索引,天然不产生重复
COUNT(DISTINCT ...) 是特例,不能多列统计
COUNT(DISTINCT col) 是常见聚合需求,用于统计某列唯一值数量。但注意:
- 语法 COUNT(DISTINCT a, b) 在绝大多数数据库中非法(SQL Server、MySQL、PostgreSQL 均不支持)
- 如需统计 (a,b) 组合数,得套一层子查询:SELECT COUNT(*) FROM (SELECT DISTINCT a, b FROM t) AS tmp
- 该操作内部仍走排序或哈希,大数据量时性能敏感,建议对 a、b 建联合索引
和 GROUP BY 的本质区别
DISTINCT 和 GROUP BY 都能输出唯一行,但定位不同:
- DISTINCT 只做去重,不支持聚合函数,语义清晰、写法简洁
- GROUP BY 是分组机制,必须配合 COUNT/SUM/MAX 等才能有意义,即使只写 GROUP BY a, b,也隐含“每组取一行”的逻辑
- 某些数据库(如 PostgreSQL)在执行计划中会把 DISTINCT 重写为 GROUP BY,但用户无需干预,按语义选即可










