SQL中DISTINCT是如何去重的?

来源:Golang编程网作者:韦伯头衔:草根站长
导读:本期聚焦于小伙伴创作的《SQL中DISTINCT是如何去重的?》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《SQL中DISTINCT是如何去重的?》有用,将其分享出去将是对创作者最好的鼓励。

SQL中的DISTINCT关键字用于对查询结果集进行去重,它的核心作用是返回结果中不存在完全相同的行,其去重逻辑基于行的所有选中列的组合值是否完全一致来判断。

SQL中DISTINCT是如何去重的?

DISTINCT的基本去重规则

DISTINCT的去重判断是基于SELECT后面跟随的所有列的值组合来进行的,只有当所有选中列的值都完全相同时,才会被判定为重复行,最终只保留其中一行。

单列去重场景

当只对单列使用DISTINCT时,会去掉该列值重复的所有行,只保留每个不同值对应的一行。比如有一张用户表user_info,结构如下:

iduser_namecity
1张三北京
2李四上海
3王五北京
4赵六广州
5张三深圳

如果要查询所有不重复的城市,使用如下SQL:

-- 查询不重复的城市
SELECT DISTINCT city FROM user_info;

执行结果会返回北京、上海、广州、深圳四个城市,原本表中北京出现了两次,去重后只保留一次。

多列去重场景

当SELECT后面跟随多列时,DISTINCT会判断这些列的组合值是否重复,只有所有列的值都完全相同时才会去重。比如查询不重复的用户名和城市组合:

-- 查询不重复的用户名和城市组合
SELECT DISTINCT user_name, city FROM user_info;

执行结果会返回5行数据,因为虽然张三出现了两次,但对应的城市分别是北京和深圳,组合值不同,所以不会被判定为重复行。

DISTINCT的执行过程

DISTINCT的去重过程通常发生在SQL查询的执行阶段,大致可以分为两个步骤:

  • 第一步:先执行FROM、WHERE等子句,得到初步的结果集,这个结果集包含所有符合筛选条件的行。
  • 第二步:对初步结果集进行去重处理,数据库会对SELECT后面的所有列的值进行哈希计算或者排序,将相同的行合并,最终只保留唯一的行返回给客户端。

不同的数据库引擎实现DISTINCT的具体方式可能有差异,比如MySQL在处理DISTINCT时,如果无法使用索引,可能会先对结果集进行排序,然后遍历排序后的结果,去掉相邻重复的行;如果可以使用索引,会直接利用索引的有序性快速去重。

DISTINCT使用的注意事项

在使用DISTINCT时需要注意几个常见的问题,避免出现不符合预期的查询结果:

NULL值的处理

在SQL中,NULL代表未知值,DISTINCT会把所有的NULL值判定为相等,所以如果某列存在多个NULL值,去重后只会保留一个NULL行。比如表中city列有多个NULL值,查询DISTINCT city时只会返回一个NULL。

与ORDER BY的配合

DISTINCT之后的结果集如果需要排序,ORDER BY后面的列必须是SELECT中已经出现的列,或者是这些列的表达式,否则会报错。比如下面的SQL是不合法的:

-- 错误示例:ORDER BY的列不在SELECT中
SELECT DISTINCT city FROM user_info ORDER BY user_name;

正确的写法应该是ORDER BY后面的列是已经选中的city,或者把user_name也加入SELECT列表:

-- 正确示例1:ORDER BY选中的列
SELECT DISTINCT city FROM user_info ORDER BY city;

-- 正确示例2:把user_name加入SELECT列表
SELECT DISTINCT user_name, city FROM user_info ORDER BY user_name;

性能影响

DISTINCT操作需要对结果集进行额外的去重处理,当结果集数据量较大时,会带来一定的性能开销。如果频繁需要对某列去重,可以考虑给该列建立索引,提升DISTINCT的执行效率。另外,不要滥用DISTINCT,只有在确实需要去重的时候才使用,避免不必要的性能消耗。

简单示例验证

我们可以通过一个完整的示例来验证DISTINCT的去重逻辑,首先创建测试表并插入数据:

-- 创建测试表
CREATE TABLE test_distinct (
    id INT,
    col1 VARCHAR(20),
    col2 VARCHAR(20)
);

-- 插入测试数据
INSERT INTO test_distinct VALUES (1, 'a', 'x');
INSERT INTO test_distinct VALUES (2, 'a', 'x');
INSERT INTO test_distinct VALUES (3, 'a', 'y');
INSERT INTO test_distinct VALUES (4, 'b', 'x');
INSERT INTO test_distinct VALUES (5, NULL, 'x');
INSERT INTO test_distinct VALUES (6, NULL, 'y');

然后执行不同的DISTINCT查询:

-- 单列col1去重
SELECT DISTINCT col1 FROM test_distinct;
-- 结果:a、b、NULL,共3行

-- 多列col1和col2去重
SELECT DISTINCT col1, col2 FROM test_distinct;
-- 结果:(a,x)、(a,y)、(b,x)、(NULL,x)、(NULL,y),共5行

从结果可以清晰看到DISTINCT的去重是基于选中列的组合值来判断的,NULL值也会被合并为一个。

SQLDISTINCT去重数据库查询修改时间:2026-07-20 18:27:42

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。