我有一个PL / SQL脚本循环遍历人的记录(约400万)并执行多个更新(~100)和一个删除语句(所有这些更新和删除都在不同的表上)。我面临的问题是,一个delete语句本身需要大约一半的运行时间。我知道当你执行一个删除语句时,它需要更新索引,但我觉得它很荒谬。我目前正在使用dbms_parallel_execute
使用一个线程测试此脚本,但我计划多线程处理此脚本。
我正在执行类似于以下内容的查询:
DELETE FROM table1 t1
WHERE (t1.key1, t1.key2) IN (SELECT t2.key1, t2.key2
FROM table2 t2
WHERE t2.parm1 = 1234
AND t2.parm2 = 5678).
以下事实:
table1没有其他限制,但对table2有更多约束。
已禁用table1上的所有触发器
解释计划输出:
OPERATION OPTIONS OBJECT_INSTANCE OBJECT_TYPE OPTIMIZER SEARCH_COLUMNS ID PARENT_ID DEPTH POSITION COST CARDINALITY BYTES CPU_COST IO_COST TIME
------------------------------------ ---------------------------------------------------------------------------------------------------- -------------------------------------------- ------------------------------------ ---------------------------------------------------------------------------------------------------- -------------------------------------------- -------------------------------------------- -------------------------------------------- -------------------------------------------- -------------------------------------------- -------------------------------------------- -------------------------------------------- -------------------------------------------- -------------------------------------------- -------------------------------------------- --------------------------------------------
DELETE STATEMENT ALL_ROWS 0 0 5 5 1 36 38043 5 1
DELETE 1 0 1 1
NESTED LOOPS 2 1 2 1 5 1 36 38043 5 1
TABLE ACCESS BY INDEX ROWID 2 TABLE ANALYZED 3 2 3 1 4 1 25 29022 4 1
INDEX RANGE SCAN INDEX ANALYZED 1 4 3 4 1 3 1 21564 3 1
INDEX UNIQUE SCAN INDEX (UNIQUE) ANALYZED 2 5 2 3 2 1 1 11 9021 1 1
我想知道是否有办法让这个删除更快。我尝试做bulk delete
,但似乎没有改善运行时间。如果有任何方法可以执行所有删除,然后更新索引,我怀疑它会运行得更快。显然,从select中创建一个create table是不可能的,因为我正在从另一个表循环遍历记录(并运行多个条件)来进行删除。
答案 0 :(得分:0)
您的每次删除调用,在表2中的30m记录上运行查询,这肯定会降低性能并且还可能会产生锁定问题,从而再次降低查询速度。
我建议移出从table2中选择数据的内联查询。表2应该驱动删除并删除候选记录。它可以作为游标运行或将此数据放在临时表中。让删除在500,1000的块中执行,然后提交。可以根据结果优化此块。
删除期间的索引更新不是多余的,如果此进程在非工作时间运行,您可以禁用索引并重新创建..
答案 1 :(得分:0)
我认为如果外部查询是“小”而内部查询是“大” - 那么WHERE EXISTS可以非常高效。
尝试where where子句而不是In子句,然后检查解释计划和性能。
DELETE FROM table1 t1
WHERE
Exists (select 1
FROM table2 t2
WHERE t2.parm1 = 1234
AND t2.parm2 = 5678
AND t2.key1 = t1.key1
AND t2.key2 = t1.key2
)