我有一个项目,需要偶尔从六个不同大小的表之一删除几万行,但它们之间有大约3000万行.由于我已经给出了数据的结构,我不知道六个表中哪一个有需要删除的行,所以我必须对所有表运行所有删除.我已经针对ID列构建了一个INDEX来尝试加快速度,但是如果它能加快速度的话就可以删除它.
我的问题是,我似乎无法找到实际执行删除的有效方法.出于测试的目的,我在单个测试表上运行7384个删除行,该测试表有大约9400行.我在Oracle SQL Developer中测试了许多可能的查询解决方案:
7384个单独的DELETE陈述耗时203秒:
delete from TABLE1 where ID=1000001356443294;
delete from TABLE1 where ID=1000001356443296;
etc...
7384个单独的SELECT陈述花了57秒:
select ID from TABLE1 where ID=1000001356443294
select ID from TABLE1 where ID=1000001356443296
etc...
7384个单独的DELETE from (SELECT)陈述耗时214秒:
delete from (select ID from TABLE1 where ID=1000001356443294);
delete from (select ID from TABLE1 where ID=1000001356443296);
etc...
1个SELECT声明中有7384个OR条款,其中127.4s:
select ID from TABLE1 where ID=1000001356443294 or ID = 1000001356443296 or ...
1个DELETE from (SELECT)声明中有7384个OR条款,其中74.4s:
delete from (select ID from TABLE1 where ID=1000001356443294 or ID = 1000001356443296 or ...)
虽然最后一个可能是最快的,但在进一步测试时,从9000行表扩展到甚至只有200,000行表(仍然是最终表集大小的1%)时仍然非常慢,其中相同的语句需要14分钟到跑.虽然每行速度提高了50%以上,但在针对完整数据集运行时仍然可以推断大约一天.我有充分的权威,我们用来完成这项任务的软件可以在大约20分钟内完成.
所以我的问题是:
- 有更好的删除方法吗?
- 我应该使用一轮
SELECT语句(例如,像第二个测试)来发现任何给定行所在的表,然后拍摄删除查询?即便看起来很慢但......- 我还能做些什么来加快删除速度吗?我没有DBA级别的访问权限或知识.
Ada*_*sch 15
在我的问题得到解答之前,我就是这样做的:
尽量减少报表的数量以及它们相对发布的工作量.
所有情景假设你有ID的(表PURGE_IDS)中进行删除TABLE_1,TABLE_2等等.
考虑使用CREATE TABLE AS SELECT进行非常大的删除
如果没有并发活动,并且您要删除一个或多个表中30%以上的行,请不要删除; create table as select使用您希望保留的行执行a ,并将旧表交换为旧表.  INSERT /*+ APPEND */ ... NOLOGGING如果你负担得起,它的价格便宜得多.即使您确实有一些并发活动,也可以使用Online Table Redefinition来就地重建表.
不要运行您知道不会删除任何行的DELETE语句
如果六个表中的至多一个表中存在ID值,则跟踪您已删除的ID - 并且不要尝试从任何其他表中删除这些ID.
CREATE TABLE TABLE1_PURGE NOLOGGING
AS 
SELECT ID FROM PURGE_IDS INNER JOIN TABLE_1 ON PURGE_IDS.ID = TABLE_1.ID;
DELETE FROM TABLE1 WHERE ID IN (SELECT ID FROM TABLE1_PURGE);
DELETE FROM PURGE_IDS WHERE ID IN (SELECT ID FROM TABLE1_PURGE);
DROP TABLE TABLE1_PURGE;
并重复.
如果必须,管理并发
另一种方法是在表上使用PL/SQL循环,发出rowcount-limited delete语句.如果对正在运行删除的表进行重大的插入/更新/删除并发加载,这很可能是合适的.
declare
  l_sql varchar2(4000);
begin
  for i in (select table_name from all_tables 
             where table_name in ('TABLE_1', 'TABLE_2', ...)
             order by table_name);
  loop
    l_sql := 'delete from ' || i.table_name || 
             ' where id in (select id from purge_ids) ' || 
             '   and rownum <= 1000000';
    loop
      commit;
      execute immediate l_sql;
      exit when sql%rowcount <> 1000000;  -- if we delete less than 1,000,000
    end loop;                             -- no more rows need to be deleted!
  end loop;
  commit;
end;
| 归档时间: | 
 | 
| 查看次数: | 103916 次 | 
| 最近记录: |