在開發中,遇到了多次需要刪除重復數據並且根據條件保留一條的情況,因此就做個總結。
以此表為例:
-- 用戶表 create table t_user ( id bigint auto_increment primary key, name varchar(20) not null, password varchar(20) not null, lessee_id int not null ) comment '用戶表'; create index idx_name on t_user (name);
原始數據:

三種方式
目標:刪除重復數據,保留ID最大的一條
-- 第一種 DELETE t1 FROM t_user t1, t_user t2 WHERE t1.lessee_id = t2.lessee_id AND t1.name = t2.name AND t1.id < t2.id; -- 第二種 delete from t_user where id not in ( (select t1.max_id from (select max(id) as max_id from t_user group by name, lessee_id having count(1) > 1) t1)) and (lessee_id, name) in (select t2.lessee_id, t2.name from (select lessee_id, name from t_user group by name, lessee_id having count(1) > 1) t2); -- 第三種 delete from t_user where id not in (select * from (select max(id) from t_user group by name, lessee_id) t2);
效率對比
往表中插入測試數據:
DELIMITER $$ CREATE PROCEDURE pro_copy() BEGIN SET @i=1; -- 起始 WHILE @i<=500000 DO INSERT INTO t_user(NAME,password,lessee_id) VALUES(CONCAT('user',@i),'123',5); -- 拼接USER 和i值 SET @i=@i+1; -- 防止成為死循環 END WHILE; -- 結束循環 END $$ -- 結束自定義結束符 DELIMITER ; call pro_copy(); -- 調用函數
方式 |
20w數據去重耗時(name無索引) |
50w數據去重耗時(name有索引) |
第一種 |
3min以上 |
3s 523ms 左右 |
第二種 |
6s 172ms 左右 |
16s 726ms 左右 |
第三種 |
3s 868ms 左右 |
13s 656ms 左右 |
結論
在查詢條件有索引的情況下,選擇第一種去重方式,沒有索引的情況下選擇第三種。