我使用的是Oracle 10g,并希望从人员表中删除大约500万条记录(共有1500万条记录),这些记录在订单表中没有任何引用(总共有500万条记录)
由于一次性检测500万条记录会导致撤消日志问题,我决定批量删除100k。我使用以下查询:
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?
P.S。这只是一次性操作,我不能使用任何DDL操作,但是pl / sql很好
答案 0 :(得分:4)
根据我的经验,删除大量行的最快方法是:
解决方案1(由Tom Kyte推荐)
`SET TRANSACTION USE ROLLBACK SEGMENT <your_seg>
DELETE FROM <tab1> WHERE <cond>
COMMIT`
OR
解决方案2
`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;
`
我在不同的上下文中使用了第二种解决方案:删除大量行总是最快的。
另一种方法是将数据放入分区中删除然后删除分区(每个分区都有自己的回滚段,可以使用并行性,......)。
答案 1 :(得分:3)
如果希望此查询运行得更快,请添加以下两个索引:
create index idx_persons_city_pid on persons(city, p_id);
create index idx_orders_pid on orders(p_id);
答案 2 :(得分:2)
DECLARE
v_limit PLS_INTEGER :=100000;
CURSOR person_deleted_cur
IS
SELECT rowid
FROM Persons p
WHERE City = 'ABC'
AND NOT EXISTS
(SELECT O_Id
FROM Orders o
WHERE p.P_Id = o.P_Id);
TYPE person_deleted_nt IS TABLE OF person_deleted_cur%ROWTYPE
INDEX BY PLS_INTEGER;
BEGIN
OPEN person_deleted_cur;
LOOP
FETCH person_deleted_cur
BULK COLLECT INTO person_deleted_nt LIMIT v_limit;
FORALL indx IN 1 .. person_deleted_nt.COUNT
DELETE FROM Persons WHERE rowid=person_deleted_nt(indx);
EXIT WHEN person_deleted_cur%NOTFOUND;
END LOOP;
CLOSE person_deleted_cur;
COMMIT;
END;
/
答案 3 :(得分:0)
还有一种删除方式:
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;