Sql 如何批量删除Oracle表中的大量数据

Sql 如何批量删除Oracle表中的大量数据,sql,database,oracle,oracle10g,Sql,Database,Oracle,Oracle10g,我正在使用Oracle 10g,希望从Persons表中删除约500万条记录,该表共有1500万条记录,而Order表中没有任何引用,总共有500万条记录 由于一次性删除500万条记录会导致撤消日志问题,因此我决定批量删除10万条记录。我正在使用以下查询: DELETE FROM Persons p WHERE City = 'ABC' AND NOT EXISTS (SELECT O_Id

我正在使用Oracle 10g,希望从Persons表中删除约500万条记录,该表共有1500万条记录,而Order表中没有任何引用,总共有500万条记录

由于一次性删除500万条记录会导致撤消日志问题,因此我决定批量删除10万条记录。我正在使用以下查询:

DELETE FROM Persons p
      WHERE     City = 'ABC'
            AND NOT EXISTS
                   (SELECT O_Id
                      FROM Orders o
                     WHERE p.P_Id = o.P_Id)
            AND ROWNUM <= 100000
现在的问题是,这个查询执行100k条记录所需的时间与执行500万条记录所需的时间一样长,因为仍然会对两个表进行完整的表扫描和联接

是否有有效的方法重写此查询以加快执行? 或者用更好的联接条件替换NOT EXISTS子句? 或者使用更好的方法将记录限制在100k


另外,这是一个一次性操作,我不能对此使用任何DDL操作,但是pl/sql很好

如果希望此查询运行得更快,请添加以下两个索引:

 create index idx_persons_city_pid on persons(city, p_id);
 create index idx_orders_pid on orders(p_id);

还有一种删除方法:

begin
  dbms_errlog.create_error_log('PERSONS');
end;
/

-- index on foreign key is useful thing in many cases, not only now
create index idx_orders_pid on orders(p_id); 

declare 
  min_id number;
  max_id number;
begin
  select min(p_id), max(p_id)
    into min_id, max_id
    from persons;

  for i in min_id..max_id loop
    delete from persons where p_id between i and i + 100000
    log errors into err$_persons reject limit unlimited;
  end loop;
end;
/

drop table err$_persons;

根据我的经验,删除大量行的最快方法是:

Tom Kyte推荐的解决方案1

`SET TRANSACTION USE ROLLBACK SEGMENT <your_seg>
 DELETE FROM <tab1> WHERE <cond>
 COMMIT`
我在不同的上下文中使用了第二种解决方案:删除大量行总是最快的


另一种方法是将要删除的数据放在一个分区中,然后删除该分区。每个分区都有自己的回滚段,可以使用并行性

您是否在OrdersP_ID上有索引?没有,只有主键上有索引,即PersonsP_ID和OrdersO_ID@dusk7您是否尝试根据国家/地区对人员创建不同的分区?还要在Orders和city中的p_id上添加索引,在Persons中的p_id上添加索引我希望避免添加索引,因为这只是一次操作。您是否尝试过对所需的值使用create as select,然后删除旧表?我想这可能很快。我想避免添加索引,因为这只是一次操作。我知道如果没有索引,查询速度会很慢,但如果查询可以稍微调整一下,那么添加索引的速度会比您想象的快得多。您可以添加索引,执行所需的处理,然后删除它们。我尝试了索引。早些时候计数大约需要300秒,现在需要100秒。等待30分钟后取消删除。这方面没有多大改善respect@dusk7:如果你不想坐下来批量删除,试试这段PL/SQL代码,它会批量删除限制1000000的记录是的,会先在测试环境中尝试:不会减少执行时间:@Dash7:Yup它不会减少执行时间,你可以按照Gordon Linoff提到的步骤执行,然后运行我的代码。最基本的问题是如何获取数据,如果进行了适当的索引,那么数据的获取速度会更快,因此执行速度也会更快。我的解决方案是,如果您不想坐在办公室等待每个批处理的执行,然后运行我的代码并返回,您可以稍后看到结果:是否需要循环?,我认为fetch足以将值放入集合这取决于线性增长的ID序列,如果重新分配ID序列,这将破坏数据的一致性
`SET TRANSACTION USE ROLLBACK SEGMENT <your_seg>
 DELETE FROM <tab1> WHERE <cond>
 COMMIT`
`create table new_table unrecoverable as select * from old_table where ....;
drop table old_table;
rename new_table to old_table;
create index old_table_idx1 on old_table(c1,c2) unrecoverable parallel 5;
`