SELECT DISTINCT 对所有SELECT列的组合去重,非单列;NULL被视为相同值;ORDER BY字段须在SELECT列表中;性能差因隐式GROUP BY;不可替代GROUP BY的聚合功能。

SELECT DISTINCT 会去重哪几列
DISTINCT 作用于 SELECT 后面的**所有列组合**,不是单列。比如 SELECT DISTINCT name, age FROM users,返回的是 (name, age) 这一对值不重复的所有行,哪怕 name 单独看有很多重复也没关系。
常见错误是以为加了 DISTINCT 就能“把 name 去重”,结果发现还是有重复 name —— 那是因为其他列(比如 id 或 created_at)不同,整行仍被视为唯一。
- 只想要不重复的
name?写成SELECT DISTINCT name FROM users - 想按
name去重但保留最新一条记录?DISTINCT做不到,得用GROUP BY+ 聚合函数或窗口函数 - 数据库对
NULL的处理一致:多个NULL被视为相同值,会被合并为一个
ORDER BY 和 DISTINCT 能不能一起用
可以,但 ORDER BY 的字段必须出现在 SELECT DISTINCT 的列列表中(SQL 标准要求),否则多数数据库(如 PostgreSQL、SQL Server)直接报错:ERROR: SELECT DISTINCT ON expressions must match initial ORDER BY expressions。
MySQL 稍宽松,允许 ORDER BY 引用未选中的列,但结果不可靠 —— 因为去重后“哪一行留下来”是不确定的,排序可能失效。
- 安全写法:
SELECT DISTINCT city FROM stores ORDER BY city - 错误写法:
SELECT DISTINCT city FROM stores ORDER BY created_at(created_at没出现在SELECT中) - 真要按时间排序又只取城市?先
GROUP BY city再MAX(created_at),或者用子查询
DISTINCT 在大数据量下为什么慢
因为 DISTINCT 本质是隐式 GROUP BY,数据库必须把所有匹配行拉出来、逐个比较整行值、再合并 —— 没索引时就是全表扫描 + 内存排序/哈希,I/O 和 CPU 开销都大。
尤其当 SELECT DISTINCT 包含文本字段(如 TEXT、JSON)或宽表多列时,性能断崖式下跌。
- 检查执行计划:留意是否有
HashAggregate或Sort + Unique步骤 - 能加索引就加:比如
CREATE INDEX idx_user_status ON users(status),对SELECT DISTINCT status FROM users有帮助 - 替代方案:如果只是校验唯一性,用
EXISTS或COUNT(DISTINCT ...)可能更轻量
用 DISTINCT 替代 GROUP BY 容易出什么问题
很多人看到 SELECT DISTINCT a, b 和 SELECT a, b FROM t GROUP BY a, b 结果一样,就以为二者等价 —— 实际上 DISTINCT 是纯去重操作,GROUP BY 是分组基础,后者才能接聚合函数。
一旦你需要“每个 city 对应的用户数”,DISTINCT 就完全无能为力,硬套只会漏数据或报语法错。
- 错误尝试:
SELECT DISTINCT city, COUNT(*) FROM stores→ 报错:column "stores.city" must appear in the GROUP BY clause - 正确做法:
SELECT city, COUNT(*) FROM stores GROUP BY city - 还有一种坑:用
DISTINCT处理关联查询时,因 JOIN 产生笛卡尔积,去重后行数看似合理,但实际丢失了聚合语义,后续统计全不准
去重只是表层动作;真正要分组统计、取最新/最老记录、拼接字符串,绕不开 GROUP BY 或窗口函数。别让 DISTINCT 承担它不该扛的逻辑。

















