分类: Oracle
2008-10-14 09:46:07
用partition by,order by方式高效删除重复记录的方法:
但在任何情况下,我删除重复记录的方法都有点儿不同。通过使用统计分析法生成要删除的rowids(行号)集,然后删除它们,就像这样,我们要删除表t以cust_seg_nbr字段重复的记录:
SQL> select count(*),
2 count(distinct cust_seg_nbr)
3 from t;
COUNT(*) COUNT(CUST_SEG_NBR)
--------- -------------------
1871652 756667
在这儿你能看到,我有180多万行,但只有756667行是唯一的。我需要删除大约110万行(很多吧)。让我们看看能多快做到这一点:
delete from t
where rowid in
(select rid
from
(select rowid rid,
row_number() over
(partition by
cust_seg_nbr
order by rowid) rn
from t
)
where rn <> 1
)
1114985 rows deleted.
Elapsed: 00:01:46.06
SQL> select count(*),
2 count(distinct cust_seg_nbr)
3 from t;
COUNT(*) COUNT(DISTINCTCUST_SEG_NBR)
--------- ---------------------------
756667 756667
如果你担心UNDO空间不足,可以考虑以下方法
还有,在我的例子中,该表没有索引。每个索引都将增加一些处理时间。请考虑像这样取消索引以便进行删除大量记录的操作,然后重新建索引。在你计划从中要删除大部分数据的大数据块操作中,维护索引可能代价很大。
至于回滚段的大小,则必须保证进行删除所需的空间。你的每一个索引都将除了使删除操作需要更多的时间之外,还需要更多的空间。
另一个删除大批数据很有效的可选方法就是建立一个保留正确记录的新表,删除旧表,就象下面的例子这样:
SQL> select count(*),
2 count(distinct cust_seg_nbr)
3 from t;
COUNT(*) COUNT(CUST_SEG_NBR)
--------- -------------------
1871652 756667
create table t2
as
select cust_seg_nbr, ...
from
(select t.*,
row_number() over
(partition by cust_seg_nbr
order by rowid) rn
from t
)
where rn = 1
/
Table created.
Elapsed: 00:00:10.93
正如你所看到的那样,本例用了11秒钟来拷贝要保留的行,而删除你不需要的行则用了1分46秒,而且这么做不必生成任何启动所需的UNDO(回滚)或REDO。