You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle逐行删除操作完成后进程仍长时间运行原因排查

问题:逐行DML完成后会话仍持续运行的原因?

我执行以下Oracle代码时耗时极长:

create table tmp$_mkemp_2 (id number generated by default on null as identity primary key, c1 varchar2 (30), c2 varchar2 (30))
/

set timing on serveroutput on size unlimited linesize 32767 pagesize 50000 trimspool on tab off feedback on heading on verify on
define svTableName = tmp$_mkemp_2
define svInsertHowMany = 500000
define svFetchRate = 2000
define svUpdateWhichMod = 2
define svDeleteWhichMod = 10
col ts format a20
col cnt format a10
<<s01_row_by_row_rbr_dml>> begin <<rbr_loop>> for iRec in (select dbms_random.string ('p', 10) c1, level id from dual connect by level <= &svInsertHowMany) loop
          insert into &svTableName (c1) values (iRec.c1);
          if mod (iRec.id, &svFetchRate) = 0 then commit; end if; end loop rbr_loop; commit;
     <<update_loop>> for iUpdateRec in (select id, c1 from &svTableName) loop
          update &svTableName set c2 = substr (c1, 1, 2) || ' ## ' || id where mod (id, &svUpdateWhichMod) = 0 and id = iUpdateRec.id;
          if mod (iUpdateRec.id, &svFetchRate) = 0 then commit; end if; end loop update_loop; commit;
     <<delete_loop>> for iDeleteRec in (select id, c1 from &svTableName) loop
          delete &svTableName where id = iDeleteRec.id and mod (iDeleteRec.id, &svDeleteWhichMod) = 0;
          if mod (iDeleteRec.id, &svFetchRate) = 0 then commit; end if; end loop delete_loop; commit;
     end s01_row_by_row_rbr_dml;
/
select to_char (sysdate, 'mm/dd/yyyy hh24:mi:ss') ts from dual
/
select count (0) cnt from &svTableName
/

当从另一个会话查看表计数时,显示为450000,说明delete_loop的实际删除操作已完成(耗时约10分钟),但原会话的进程仍持续运行数小时。
该问题在更小数据集下可复现:插入50000行时,删除完成(表剩余45000行)耗时约1分钟,但整个进程需6分钟才结束。

我知晓这并非正确的数据处理方式,但希望了解该方式的运行性能细节,请问为何工作完成后事务仍持续运行?


原因分析

  • 一致性读快照的特性:delete_loop的游标基于select id, c1 from &svTableName打开时,Oracle会创建一个一致性读快照,这个快照记录了游标打开瞬间的数据状态。后续循环中即使删除了行,游标仍需遍历快照中的所有原始行(包括已被删除的行),直到游标完全耗尽——也就是说,哪怕物理上已经删除了10%的行,循环还是要走完最初的50万次迭代,大部分迭代只是执行无实际效果的delete判断。
  • 频繁提交不影响游标遍历:每2000行提交一次的操作,只会提交当前事务的修改,但不会改变游标的一致性读快照。游标会持续基于初始快照完成所有行的遍历,不会因为数据的实时变化提前终止。
  • 逐行处理的固有低效放大:逐行DML本身就远低于批量操作的效率,而这里的游标逻辑没有适配数据变化,导致删除完成后仍要执行大量无意义的循环迭代,这是进程长时间运行的核心原因。

内容的提问来源于stack exchange,提问作者M. Kemp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 13:23:27