distinct只对select整行去重,非单字段;仅当所有选中列值完全相同时才合并,否则保留多行。

SELECT DISTINCT 能去重,但只对整行生效
很多人以为 DISTINCT 是“按某列去重”,其实它作用于整个 SELECT 列表。只要两行在所有选中的字段上完全一致,才视为重复。比如:
SELECT DISTINCT dept, salary FROM employees;
这会保留所有 (dept, salary) 组合唯一的记录,不是单纯按 dept 去重。
- 如果只想看不重复的部门名,必须只选
dept:SELECT DISTINCT dept FROM employees; - 一旦加上
name或id,几乎必然失去去重效果——因为每个人名字不同 -
DISTINCT在执行时需排序或哈希去重,大数据量下性能明显低于普通查询
需要“每组取一条”时,DISTINCT 不够用
比如“每个部门薪资最高的人”,DISTINCT 完全无法解决。它不能配合 ORDER BY 或聚合函数做行级筛选。
- 常见错误写法:
SELECT DISTINCT dept, MAX(salary) FROM employees;—— 缺少GROUP BY dept会报错(MySQL 5.7+ 严格模式) - 真正需求往往是“去重后还要带其他字段”,这时得用窗口函数或子查询
- PostgreSQL / SQL Server / Oracle 可用
ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC)配合外层WHERE rn = 1 - MySQL 8.0+ 支持窗口函数;老版本只能靠自连接或相关子查询,易出错且慢
DISTINCT 和 GROUP BY 的区别不只是语法
表面看 SELECT DISTINCT a, b 和 SELECT a, b FROM t GROUP BY a, b 结果一样,但语义和能力完全不同。
-
GROUP BY允许搭配聚合函数:SELECT dept, COUNT(*), AVG(salary) FROM employees GROUP BY dept; -
DISTINCT后不能直接跟聚合,也不能加HAVING过滤分组结果 - 某些引擎(如 ClickHouse)对
GROUP BY有更多优化,而DISTINCT可能被降级为临时表去重 - 当字段含
NULL,多数数据库把所有NULL视为相等,DISTINCT会合并它们——这点和=比较逻辑不一致,容易被忽略
替代方案:用 EXISTS 或 IN 处理逻辑更复杂的“去重”
当去重要求依赖另一张表、或需排除特定状态记录时,DISTINCT 往往力不从心。
- 例如:“查所有有订单的客户姓名”,用
SELECT DISTINCT name FROM customers c JOIN orders o ON c.id = o.customer_id;可行,但若订单表很大,JOIN 可能产生大量中间行 - 改用
EXISTS更清晰高效:SELECT name FROM customers c WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id); - 注意:如果
customers.name允许重复,而你又想确保姓名唯一,仍得在外层套DISTINCT或改用GROUP BY - 别在
WHERE子句里滥用IN (SELECT DISTINCT ...),子查询若返回 NULL,整个条件可能意外失效
DISTINCT 很快,但错一步就得不到想要的结果。










