今天遇到一个需要对表进行去重的问题,数据量大概千万左右,第一选择就是按Oracle的思路上:
delete from table t1 where id < (select max(id) from table t2 where t1.c1=t2.c1); --将c1值相同的记录进行去重,只留下id最大的,写成id>min(id)效果相同。
以上相关子查询的SQL在c1上存在索引时效率不算低,但是很遗憾MySQL没有这种写法,类似的替代写法在MySQL中效率也低的令人发指,如中间表等手段。
正好在前些时间整理一些shell脚本时处理过mysql导入时出错继续执行的问题,因此测试后采用了如下办法:
1.将表数据导出:
mysqldump -uroot -p --skip-extended-insert -t DBNAME TABLE>TABLE.sql
然后记一下去重后的记录数:select count(*) from (select 1 from TABLE group by c1) a;
2.truncate表,然后创建唯一索引
truncate table TABLE;create unique index IX_c1 on TABLE(c1);
3.最后导入数据,需要添加-f选项。
mysql -uroot -p -f DBNAME
-f的作用是:Continue even if an SQL error occurs.
这样导入时会报很多的错误,就是因为唯一约束的存在,你只需要最后检查下表的记录数时候与第一步中查到的数目一致就可以了。
这种去重方式效率比较高,缺陷可能是出错时屏幕上一堆的‘Duplicate entry’报错会淹没其他的报错。
此外还可以写存储过程来删除重复数据,这种方式对数据库的影响较小,无需导出导入数据,存储过程写法详见: