MySQL数据去重完整教程:重复记录查询、保留一条与批量删除

MySQL 表里出现重复数据,是很多业务都会遇到的问题。比如用户重复注册、商品重复导入、订单外部编号重复、日志重复写入、采集数据重复入库等。如果不及时处理,后续统计、查询和业务判断都会受到影响。

数据去重不能一上来就删除。正确流程应该是先确认重复规则,再查询重复记录,备份数据,最后选择保留哪一条并批量删除。本文从重复记录查询讲起,再整理保留一条和防止再次重复的方法。

先明确去重规则

去重前必须明确:按哪个字段判断重复?是单字段重复,还是多个字段组合重复?保留最早一条,还是保留最新一条?

比如用户表可能按邮箱去重,订单表可能按外部订单号去重,商品表可能按店铺 ID 和商品编码共同去重。规则不明确,删除就很危险。

查询重复值

可以使用 GROUP BYHAVING 查询重复字段。

SELECT email, COUNT(*) AS total
FROM users
GROUP BY email
HAVING total > 1;

这能找出哪些邮箱出现了多次,但还看不到具体重复记录。下一步要查询这些重复值对应的完整数据。

MySQL数据去重教程配图:重复记录查询与批量删除
MySQL 去重前一定要先确认规则和备份数据,避免误删有效记录。

查看重复记录

查出重复值后,可以关联原表查看完整记录。

SELECT * FROM users
WHERE email IN (
  SELECT email FROM (
    SELECT email
    FROM users
    GROUP BY email
    HAVING COUNT(*) > 1
  ) t
)
ORDER BY email, id;

这里多套一层子查询,是为了避免某些 MySQL 场景下对子查询的限制。查看完整记录后,再决定保留策略。

按多个字段去重

如果重复规则由多个字段组成,可以在 GROUP BY 中写多个字段。

SELECT shop_id, sku, COUNT(*) AS total
FROM products
GROUP BY shop_id, sku
HAVING total > 1;

多字段去重更符合真实业务。比如同一个 sku 在不同店铺可以重复,但同一店铺内不能重复。

保留最小 ID

最常见的去重策略是保留每组中 ID 最小的一条,删除其他重复记录。

SELECT MIN(id) AS keep_id
FROM users
GROUP BY email;

保留最小 ID 通常表示保留最早创建的数据。但如果后来的记录更新更完整,就可能应该保留最大 ID 或按更新时间选择。

删除重复数据

保留最小 ID 并删除其他记录,可以使用自连接删除。

DELETE u1 FROM users u1
JOIN users u2
  ON u1.email = u2.email
 AND u1.id > u2.id;

这条 SQL 的意思是:同一个 email 下,如果 u1 的 id 更大,就删除 u1,保留较小 id。执行前一定要先用 SELECT 模拟确认。

先 SELECT 再 DELETE

任何批量删除前,都应该先把 DELETE 改写成 SELECT 看看会删哪些记录。

SELECT u1.* FROM users u1
JOIN users u2
  ON u1.email = u2.email
 AND u1.id > u2.id;

确认结果无误后,再执行 DELETE。重要数据还要先备份,不能直接在生产库上盲删。

保留最新记录

如果希望保留最新记录,可以把条件反过来,删除 id 更小的记录。

DELETE u1 FROM users u1
JOIN users u2
  ON u1.email = u2.email
 AND u1.id < u2.id;

如果最新不等于最大 ID,而是按更新时间判断,就应该使用 updated_at 或业务时间字段设计规则。

使用临时表

复杂去重场景可以先把要保留的 ID 写入临时表,再删除不在保留名单里的记录。这样步骤更清晰,也便于人工检查。

CREATE TEMPORARY TABLE keep_users AS
SELECT MIN(id) AS id
FROM users
GROUP BY email;

然后再根据临时表删除重复数据。对生产数据来说,分步骤比一条复杂 SQL 更容易控制风险。

批量删除控制

如果重复数据很多,不建议一次性删除几十万行。可以分批删除,降低锁表、复制延迟和业务抖动风险。

DELETE FROM users
WHERE id IN (...)
LIMIT 1000;

实际批量清理时,要结合业务低峰期、备份和监控一起执行。

防止再次重复

清理完重复数据后,应该从源头防止再次出现。最有效的方法是增加唯一索引或联合唯一索引。

ALTER TABLE users ADD UNIQUE KEY uniq_email (email);

如果是多字段唯一,则建立联合唯一索引。

ALTER TABLE products ADD UNIQUE KEY uniq_shop_sku (shop_id, sku);

插入时处理冲突

有唯一索引后,插入重复数据会失败。可以根据业务使用 INSERT IGNOREON DUPLICATE KEY UPDATE

INSERT INTO users (email, name)
VALUES ('demo@example.com', 'Demo')
ON DUPLICATE KEY UPDATE name = VALUES(name);

这类写法要谨慎使用,明确是忽略重复还是更新已有记录。

常见错误

第一种错误是没明确重复规则就删除。第二种错误是没有备份。第三种错误是直接 DELETE,不先 SELECT 确认。第四种错误是清理后不加唯一约束,重复数据很快又出现。第五种错误是一次删除太多导致业务抖动。

实践建议

MySQL 数据去重建议按流程来:定义重复规则,查询重复分组,查看完整重复记录,确认保留策略,备份数据,先 SELECT 验证,再分批 DELETE,最后增加唯一索引或导入约束。

去重不是单纯写一条删除 SQL,而是一次数据治理动作。安全、可回滚、能防止复发,才算真正处理完成。

© 版权声明
THE END
喜欢就支持一下吧
点赞7 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容