好,咱们直接聊数据库里的DISTINCT。

做数据库开发或者数据分析的朋友,肯定都跟DISTINCT打过交道。这词儿看着简单,用起来也没啥门槛,就是“去重”嘛。但你要是真以为它就是个一键去重的开关,那八成会在某些时候翻车。今天咱们就掰扯掰扯,DISTINCT到底是个啥玩意儿,怎么用才算聪明,哪些坑你千万别踩。
先说最基础的场景。你手头有张订单表,里面存着几千条记录,客户名、商品名、下单日期乱七八糟混在一起。老板突然问:“咱这个月到底有多少个客户买过东西?”你第一反应肯定是SELECT DISTINCT customername FROM orders。跑出来一看,重复的客户名没了,干净利落。这时候DISTINCT干的事儿特别简单:把结果集里的每一行都跟其他行比一比,但凡所有字段都一模一样的,只留一条。
但问题来了。你试试SELECT DISTINCT * FROM orders,然后看结果,八成是全部记录,一条都不少。为啥?因为每条订单的主键不一样,或者时间戳不一样,哪怕客户、商品都一样,DISTINCT也会认为这是不同的行。所以记住,DISTINCT是整行去重,不是某一列去重。你要是只想看某个字段的唯一值,别用DISTINCT,用GROUP BY加该字段,性能还更好。
说到性能,这是DISTINCT最容易让人头大的地方。数据量小的时候,DISTINCT跑得飞快,你根本感觉不到。但当你有个几百万行的表,还带着好几个JOIN,再甩一个DISTINCT上去,数据库就得把所有数据先排序或者建哈希表,然后才能找出唯一的行。排一次序,对于大表来说,I/O开销和CPU消耗都是成倍增加的。我见过一个案例,某系统有个查询本来跑两秒,加了个DISTINCT之后直接飙到二十秒,领导以为系统挂了。
那什么时候该用DISTINCT?有两个典型场景。第一个是快速了解表里某个字段有哪些不同的值,比如查一下产品类别有多少种,或者客户分布在哪些城市。这种查询通常数据量不大,或者你加了条件过滤,DISTINCT能帮你快速拿到一个干净的清单。第二个场景是跨表查询时,因为JOIN产生了重复行,但你只需要不重复的结果。比如订单表和商品表关联,一个订单可能包含多个商品,每行都带订单信息,你只想要不重复的订单号,这时候DISTINCT就派上用场了。
但你要小心,DISTINCT不是万能的去重工具。有时候重复行是因为数据质量本身有问题,比如用户重复交了两次订单,或者系统写入了两次。这时候用DISTINCT只是掩盖了问题,该修数据还得修。另外,DISTINCT也不能帮你区分“到底哪个版本是准确的”。如果同一客户有两个手机号,DISTINCT只会告诉你有两个不同的手机号,不会告诉你哪个是当前在用的。这种场景,你得用窗口函数ROWNUMBER()配合PARTITION BY来做更精细的去重。
还有一个容易混淆的点:DISTINCT和GROUP BY到底有啥区别?功能上,两者都能去重,但GROUP BY更强,因为它可以配合聚合函数,比如COUNT、SUM、AVG、MAX、MIN,还能按多个维度分组。而DISTINCT只能告诉你“存在哪些不同的组合”,不能做聚合计算。所以如果你只是想知道“有哪些不同的值”,DISTINCT更简洁;如果你要“按某个字段分组并统计”,那就得用GROUP BY。有个小技巧:如果你只需要去重一个字段,用GROUP BY那一个字段,后面再SELECT其他字段,效率可能比DISTINCT高,因为GROUP BY可以利用索引,而DISTINCT有时会强制全表扫描。
再聊聊多列DISTINCT。写法很简单:SELECT DISTINCT col1, col2 FROM table。这会把两列组合起来去重,意思是col1和col2都相同才视为重复。这种用法在分析用户行为时特别常见,比如想看看某个用户在某一天有没有访问过网站,就要查用户ID和日期这两个字段的组合是不是唯一的。但要注意,如果两列里有一列是时间戳或者精确到秒的日期,那基本没有重复的可能,DISTINCT也就没啥意义了。
说个你可能踩过的坑:DISTINCT和ORDER BY一起用。比如SELECT DISTINCT name FROM users ORDER BY id。这在某些数据库里会报错,因为DISTINCT去重后,id的值可能不唯一,数据库不知道该按哪个id来排序。正确的做法是ORDER BY DISTINCT的字段本身,或者用子查询先排序再DISTINCT,但那样逻辑容易乱。更稳妥的方式是先用GROUP BY取出唯一值,再排序,这样可控性更高。
总结一下,DISTINCT是数据库里一个轻量级的去重工具,用好了能省不少事,用错了就是性能黑洞。核心就三条:第一,它是整行去重,不是单列;第二,大数据量下慎用,优先考虑GROUP BY或窗口函数;第三,别拿它当数据清洗的替身,数据脏了就去清理源头。下次写SQL的时候,多问自己一句:“这个DISTINCT真的有必要吗?”如果答案是肯定的,那就放心用;如果不是,换条路试试。


