智睿享
白蓝主题五 · 清爽阅读
首页  > 网络优化

SQL查询去重的实用技巧与场景解析

在日常开发中,数据表里经常会出现重复记录。比如用户注册信息不小心被提交了两次,或者订单系统因为网络抖动生成了重复流水。这时候,怎么从数据库里把干净的数据捞出来,就成了关键问题。

DISTINCT:最直接的去重方式

当你只想查出不重复的值时,DISTINCT 是最常用的关键词。比如一张用户登录日志表,同一个用户可能多次登录,你想知道有多少不同的用户登录过:

SELECT DISTINCT user_id FROM login_log;

这样就能拿到唯一的用户ID列表。如果要按多个字段组合去重,比如查出不同用户在不同日期的登录记录:

SELECT DISTINCT user_id, DATE(login_time) FROM login_log;

GROUP BY:更灵活的去重控制

当需要在去重的同时做一些统计,比如统计每个用户的登录次数,GROUP BY 就比 DISTINCT 更合适:

SELECT user_id, COUNT(*) AS login_count FROM login_log GROUP BY user_id;

它不仅能去重,还能附带聚合信息。有时候你发现某个订单表里有完全相同的行,可以用 GROUP BY 配合 HAVING 找出重复次数大于1的记录:

SELECT order_no, COUNT(*) as cnt FROM orders GROUP BY order_no HAVING cnt > 1;

处理部分字段重复的情况

实际业务中,很少整行都一样。常见的是关键字段重复,但时间戳或状态不同。比如同一笔订单被插入了两条,只有创建时间不一样。这时候可以用窗口函数 ROW_NUMBER() 来标记重复项:

SELECT * FROM (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY order_no ORDER BY create_time DESC) as rn
  FROM orders
) t WHERE rn = 1;

这段语句的意思是:按订单号分组,每组内按创建时间倒序排,取第一条。这样就保留了最新的那条记录,其他重复的就被过滤掉了。

去重也要考虑性能

数据量一大,DISTINCTGROUP BY 都可能变慢。尤其是对大文本字段去重,数据库得做大量比对。这时候可以考虑加索引,比如在 user_idorder_no 上建索引,能明显提升去重速度。

另外,如果只是想检查是否存在重复,没必要查出所有数据,用下面这种写法更轻量:

SELECT order_no FROM orders GROUP BY order_no HAVING COUNT(*) > 1 LIMIT 10;

只看前10个重复的订单号,快速定位问题。

避免重复从源头做起

与其事后去重,不如一开始就防止重复插入。比如在数据库层面设置唯一索引:

ALTER TABLE orders ADD UNIQUE INDEX uk_order_no (order_no);

这样再插入相同订单号时,数据库会直接报错,强制程序处理异常,避免脏数据入库。

去重不是一次性任务,而是贯穿数据生命周期的操作。掌握几种常用写法,结合业务场景灵活使用,才能让查询又准又快。