SQL DISTINCT如何去重_DISTINCT执行机制分析

1次阅读

SQL DISTINCT如何去重_DISTINCT执行机制分析

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,但用户无需干预,按语义选即可
text=ZqhQzanResources