导读:本期聚焦于布兰登创作的《mysql如何删除表中完全重复的记录:ROWID法与临时表去重策略详解》,敬请观看详情。表中出现完全重复的记录是MySQL使用中常见的麻烦事,不仅浪费存储空间,还可能导致统计结果出错。本文围绕两种主流去重方案展开:一种是利用ROW_NUMBER窗口函数配合ROWID定位重复行的删除方法,另一种是创建临时表重建干净数据再回写的策略。文章详细讲解了不同MySQL版本下的SQL写法差异,包括5.7等低版本没有窗口函数时的自连接替代方案,并对比了两种方式在大表场景下的执行效率、锁表风险和操作复杂度,同时提醒操作前备份、外键约束处理等容易踩坑的细节,帮助你安全快速地清理重复数据。

当一张业务表因为程序漏洞、重复导入或者并发写入产生了完全相同的记录时,查询统计就会出现偏差,索引空间也被白白占用。所谓完全重复,指的是所有字段的值都一模一样,连主键都无法区分它们(这种情况通常发生在表没有设计主键的时候)。本文介绍两种经过实践验证的清理方案:ROWID定位删除法和临时表重建法,并针对不同版本的MySQL给出对应的SQL写法。

mysql如何删除表中完全重复的记录:ROWID法与临时表去重策略详解

一、准备工作:确认重复情况并做好备份

动手删数据之前,必须先搞清楚重复的严重程度。对于没有主键的表,可以直接用SELECT *, COUNT(*) FROM t GROUP BY 所有字段 HAVING COUNT(*) > 1来查看哪些数据出现了重复。注意GROUP BY的列表必须覆盖全部字段,否则会把只是部分相同的记录也当成重复。如果表字段很多,写起来很繁琐,可以用CONCAT_WS把所有字段拼接成一个字符串再分组,效果等价但SQL更短。

备份这一步千万不要省。最直接的方式是整表备份一份:

-- 快速备份整张表
CREATE TABLE t_backup AS SELECT * FROM your_table;

-- 确认备份行数一致后再操作
SELECT COUNT(*) FROM your_table;
SELECT COUNT(*) FROM t_backup;

备份完成后,建议在一个事务中执行删除(InnoDB引擎),这样即使误删也可以回滚。另外如果这张表被其他表通过外键引用,删除时还要注意外键约束的行为,必要时先临时关闭外键检查:SET FOREIGN_KEY_CHECKS = 0;,操作完再打开。

二、方案一:利用隐藏ROWID定位删除

InnoDB表每行都有一个隐藏的ROWID(如果表没有显式主键,系统会自动生成一个聚簇索引键)。思路是:先按所有字段分组,每组只保留一条,把要删除的行定位出来,再用DELETE配合子查询删除。MySQL 8.0提供了窗口函数,写法非常简洁:

-- MySQL 8.0 及以上版本
DELETE FROM your_table
WHERE row_id IN (
    SELECT row_id FROM (
        SELECT ctid AS row_id,
               ROW_NUMBER() OVER (
                   PARTITION BY col1, col2, col3
                   ORDER BY ctid
               ) AS rn
        FROM your_table
    ) tmp
    WHERE rn > 1
);

不过需要说明的是,MySQL的InnoDB并不像Oracle那样提供可以直接查询的物理ROWID伪列,上面的ctid思路在PostgreSQL里才可用。在MySQL中,更通用的做法是先给没有主键的表补一个自增主键,让每一行变得可区分,然后再执行删除:

-- 第一步:为无主键的表添加自增列,使每行唯一可识别
ALTER TABLE your_table ADD COLUMN rid BIGINT NOT NULL AUTO_INCREMENT,
    ADD PRIMARY KEY (rid);

-- 第二步:保留每组最小rid的记录,删除其余重复行
DELETE FROM your_table
WHERE rid NOT IN (
    SELECT min_rid FROM (
        SELECT MIN(rid) AS min_rid
        FROM your_table
        GROUP BY col1, col2, col3
    ) tmp
);

这里有一个细节值得注意:MySQL不允许DELETE语句直接引用被删除的同一张表作为子查询,所以中间必须包一层派生表(示例中的tmp),否则会报错"You can't specify target table for update in FROM clause"。很多人第一次写这个SQL都会踩到这个坑。另外,如果表里字段非常多,GROUP BY全部字段可以用GROUP BY CONCAT_WS('|', col1, col2, ...)简化,但要注意字段值中如果本身就含有分隔符,理论上存在极小概率的误判,字段可控时再使用。

三、方案二:临时表重建法

当重复数据量非常大时,逐行DELETE会产生大量undo日志和binlog,执行缓慢且主从延迟明显。此时更推荐临时表方案:先把去重后的干净数据写入新表,再用RENAME原子替换。这种方式本质上是重建数据,删除操作被转化为一次建表加一次改名,速度通常快一个数量级。

-- 第一步:创建结构相同的新表
CREATE TABLE your_table_new LIKE your_table;

-- 第二步:插入去重后的数据(DISTINCT会按所有字段去重)
INSERT INTO your_table_new
SELECT DISTINCT * FROM your_table;

-- 第三步:原子交换表名,瞬间完成
RENAME TABLE your_table TO your_table_old,
             your_table_new TO your_table;

如果只需要按部分字段去重(即保留每个分组的一条记录),DISTINCT就不够用了,可以结合GROUP BY取每组任意一条:

INSERT INTO your_table_new
SELECT * FROM your_table
WHERE rid IN (
    SELECT MIN(rid) FROM your_table
    GROUP BY col1, col2, col3
);

这种方案的主要风险在于切换瞬间:RENAME之前新旧表是两张不同的表,期间写入旧表的新数据在切换后会丢失。因此执行前最好停掉相关写入,或者选择业务低峰期操作。确认线上稳定后,再把your_table_old保留几天作为额外备份,之后DROP掉即可。此外,新表记得检查索引是否完整,CREATE TABLE ... LIKE会复制索引结构,但如果原表缺索引,正好趁此机会补上。

四、两种方案的对比与选择建议

两种方案各有适用场景,简单对比如下:

对比维度ROWID定位删除法临时表重建法
执行速度重复行少时快,重复行多时慢与数据总量相关,大表整体更快
锁影响按行加锁,间隙锁可能阻塞业务写入新表不锁旧表,RENAME瞬时完成
binlog量每删一行记一条,量大一次INSERT SELECT加RENAME,量小
操作复杂度一条SQL搞定,逻辑直观多步骤,需停写或选低峰期
适用场景重复行占比低于20%重复严重的大表、核心业务表

实际选择时可以先估算重复比例:SELECT COUNT(*) - COUNT(DISTINCT 所有字段拼接) FROM your_table得到重复行数。重复行数在一万以内的,直接用方案二的第一种SQL删除即可,几分钟内能跑完;重复行数达到百万级别,果断采用临时表重建。无论选哪种,操作前的时间点备份和操作后的行数校验都是不可省略的流程,数据安全永远排在效率前面。

MySQL删除重复记录临时表去重ROWID去重修改时间:2026-09-05 04:10:31

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