数据库-删除表中重复记录实现方法分析

来源:互联网 发布:淘大象软件下载 编辑:程序博客网 时间:2024/05/18 03:57

问题描述:数据库表中存在脏数据,多条记录含义上是相同的。含义相同记录可以通过某些列判断(逻辑标识列),此外,记录行存在其他标识列(物理标识列)。要求按照一定规则删除含义相同记录,保存其中一条。


处理思路:此类问题处理时,只能借助子查询实现。一种方法是通过子查询判断当前记录不在保留记录列表中,另一种方式是通过引用直接检测子查询满足删除规则。


实例
表T_User,主键为id列,名称列为name,索引为idx_user(name,id),若name相同,视为含义相同记录。表中记录数为20000条。要求删除重复记录,只保留id最小的记录。下面分析时以select为例,实际使用时改为delete语句。先通过查询检测正确性,让后执行修改也是一个好的工作习惯。需要注意的是delete表不能定义别名表实例。
方法1
SQL语句:
select * from t_user where exists (select 1 from t_user t2 where t2.name=t_user.name and t_user.id < t2.id)
执行计划:

运行时间:
0.158s
方法说明:

该方法运行时对当前行在子查询中直接检测。当name有可用索引时,该方法执行很快。若无索引执行时间是100+s。


方法2
SQL语句:
select * from t_user where 
(name,id) not in (select name,min(t2.id) from t_user t2 group by t2.name)
执行计划:

运行时间:
146.081s
方法说明:

该方法在子查询中先要对所有记录执行group操作,而后才进行判断。即使子查询有索引可用,由于判断阶段不能借助索引,仍然很慢。


方法3
SQL语句:
select * from t_user where 
name in(select t1.name from t_user t1 group by t1.name having count(t1.id)>1) 
and 
id not in (select min(t2.id) from t_user t2 group by t2.name having COUNT(t2.id)>1 )
执行计划:

运行时间:
259.957s
方法说明:

该方法与方法2的思路类似,但是通过两个子查询实现,运行效率上比方法2更低。


其他方法
若name无索引可用时,上述三中方法都很慢。而SQL语句:
select name,min(t.id) from t_user t group by t.name,本身执行并不不是那么慢。
实际使用中,若数据量较大,且不能直接添加索引,可考虑使用使用类似上面的SQL语句创建临时表,添加索引,而后采用方法1的思路,在子查询中使用临时表。
0 0