如何高效删除 MySQL 中重复记录(保留每组第一条)

夜宇吖_5225

夜宇吖_5225

2026-08-08

352人浏览

原创

如何高效删除 MySQL 中重复记录(保留每组第一条)

本文介绍在 laravel 项目中,针对千万级数据表(如 5000 万行)安全、高效地批量删除重复记录的完整方案:通过纯 sql 在数据库层完成去重,避免 php 循环与多次查询带来的性能灾难。

本文介绍在 laravel 项目中,针对千万级数据表(如 5000 万行)安全、高效地批量删除重复记录的完整方案:通过纯 sql 在数据库层完成去重,避免 php 循环与多次查询带来的性能灾难。

在处理大规模数据(如 5000 万行、140GB 表)时,使用 Laravel Eloquent 在 PHP 层逐组查找并删除重复记录——例如先查出所有 (codes, customer_id) 组合的重复项,再对每组执行 first() + delete() ——会引发严重性能瓶颈:单次操作涉及多次数据库往返、ORM 解析开销及大量小查询(可能超 20 万次),极易导致超时、锁表甚至服务中断。

根本解法:将去重逻辑完全下推至数据库层执行,杜绝 PHP/ORM 参与。 核心思路是:只保留每个 (codes, customer_id) 组合中 id 最小(即最早插入)的一条记录,其余全部删除。 这可通过“临时唯一表 + 反向过滤”策略实现,全程仅需数条 SQL,且可分批执行,兼顾安全性与可控性。

✅ 推荐方案:创建 ids_to_keep 临时表(安全、可控、空间友好)

-- 1. 创建轻量级临时表(仅存 id + 去重字段,无冗余数据)
CREATE TABLE ids_to_keep (
    id INT PRIMARY KEY,
    codes VARCHAR(50) NOT NULL,
    customer_id INT NOT NULL,
    UNIQUE KEY idx_codes_customer (codes, customer_id)
);

-- 2. 利用 INSERT IGNORE 的冲突忽略机制,自动保留每组首个插入的 id
INSERT IGNORE INTO ids_to_keep 
SELECT id, codes, customer_id FROM pizzas;

⚠️ 注意事项:

  • ids_to_keep 表结构必须与源表对应字段类型一致(如 codes 长度、customer_id 类型);
  • INSERT IGNORE 会跳过违反 UNIQUE 约束的后续行,因此每组 (codes, customer_id) 仅保留 首次扫描到的 id(通常为最小 id,取决于 SELECT 扫描顺序;若需严格保证最小 id,见进阶优化);
  • 此表体积极小:假设原表单行约 3KB,5000 万行共 140GB;而 ids_to_keep 仅含 id(4B)、codes(≤50B)、customer_id(4–8B),加上索引,预估总大小

? 执行删除:精准移除非保留记录

-- 方案 A:一次性删除(适用于有足够事务日志空间的环境)
DELETE FROM pizzas 
WHERE id NOT IN (SELECT id FROM ids_to_keep);

-- 方案 B:分批删除(强烈推荐!避免长事务与锁表)
DELETE FROM pizzas 
WHERE id NOT IN (SELECT id FROM ids_to_keep)
  AND id BETWEEN 1 AND 100000; -- 每次处理 10 万 ID 区间

-- 执行后检查影响行数,逐步推进区间(如 100001–200000...)

? 性能提示:执行前务必运行 EXPLAIN DELETE ... 确认查询走 id 主键索引;若 NOT IN 效率低,可改用 LEFT JOIN

MySQL
MySQL

编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。

下载
DELETE p FROM pizzas p
LEFT JOIN ids_to_keep k ON p.id = k.id
WHERE k.id IS NULL;

? 清理与防护

-- 删除临时表
DROP TABLE ids_to_keep;

-- 添加唯一约束,杜绝未来重复(关键!)
ALTER TABLE pizzas 
ADD CONSTRAINT uk_codes_customer UNIQUE (codes, customer_id);

? 进阶优化:确保保留最小 ID(精确控制)

若需 100% 保证每组保留 id 最小的记录(而非依赖 INSERT IGNORE 的扫描顺序),可改用窗口函数(MySQL 8.0+):

-- 直接生成待保留 ID 列表(无需临时表)
DELETE p FROM pizzas p
LEFT JOIN (
    SELECT id, 
           ROW_NUMBER() OVER (PARTITION BY codes, customer_id ORDER BY id) AS rn
    FROM pizzas
) ranked ON p.id = ranked.id AND ranked.rn > 1
WHERE ranked.id IS NOT NULL;

此语句直接标记每组中 rn > 1 的行(即非首条),并一次性删除,更简洁且语义明确。

? 关键总结

  • 永远先备份:对 140GB 表操作前,确保有可用、验证过的全量备份;
  • 拒绝 ORM 循环:5000 万行场景下,任何 PHP 层循环 + N+1 查询都是反模式;
  • 空间换时间:5GB 临时表代价远小于 20 万次查询的网络与 CPU 开销;
  • 分批是底线:单次 DELETE 超百万行易触发锁等待或 OOM,务必按 id 分段;
  • 约束即防线:去重完成后立即添加 UNIQUE INDEX,从源头阻断重复写入。

通过将逻辑下沉至数据库,整个去重过程可从数小时压缩至数十分钟,同时大幅降低系统负载与人为失误风险。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

mysql

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

1913

6

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.21

1179

5

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

695

5

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.19

2472

5

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.25

4028

4

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.08

959

3

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.11

4311

4

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

2023.08.14

3902

7

mysql事务隔离级别
mysql事务隔离级别

mysql规范中定义了四种事务隔离级别,不同的隔离级别对事务的处理有所不同。本专题为大家提供mysql事务隔离级别相关的文章内容,大家可以免费体验。

2023.08.16

5014

11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 169人学习

使用phpenv集成环境安装极致CMS
使用phpenv集成环境安装极致CMS

共2课时 | 271人学习