DBMS_PARALLEL_EXECUTE不能直接执行UPDATE语句,因其仅负责任务切片、分发与调度,需自行编写PL/SQL过程封装UPDATE逻辑后由框架调用;常见错误是直接传入UPDATE...WHERE ROWNUM。
DBMS_PARALLEL_EXECUTE 为什么不能直接用 UPDATE 语句?
因为 dbms_parallel_execute 本身不执行 sql,它只负责把任务切片、分发、调度;你得自己写一个 pl/sql 过程封装实际的 update 逻辑,再让并行执行框架去调用它。
常见错误是直接传入 UPDATE ... WHERE ROWNUM 这类语句——这会触发全表扫描+随机截断,数据重复或遗漏,且无法保证分区边界对齐。
- 必须用
BULK COLLECT+FORALL或基于ROWID/ 分区键范围的精准定位 - 切片方式优先选
BY ROWID(适合无业务主键场景)或BY NUMBER COLUMN(需确保列单调、非空、有索引) - 若表按时间分区,推荐用
BY RANGE配合分区名列表,避免跨分区扫描
怎么安全地切分大表更新任务?
切片不是越细越好。太细会加重协调开销;太粗则单任务失败重跑成本高,还可能锁表太久。
典型错误:用 CREATE_TASK 后立刻 CREATE_CHUNKS_BY_ROWID,却不设 chunk_size——默认按 10000 行切,但若每行 2KB,单 chunk 就占 20MB PGA,容易 OOM。
-
chunk_size建议控制在 5000–20000 行之间,具体看单行大小和并发数 - 使用
BY RANGE时,必须提前查出所有分区名:SELECT partition_name FROM user_tab_partitions WHERE table_name = 'YOUR_TABLE' - 切片后务必查
user_parallel_execute_chunks确认 chunk 数量和状态,别跳过验证
并发执行中如何避免 ORA-12838 和锁冲突?
ORA-12838: cannot read/modify an object after modifying it in parallel DML 是最常踩的坑——根本原因是 session 在并行 DML 后没提交,又试图查同一张表。
另一个隐形问题是多个 chunk 更新同一分区键值(比如都更新 status = 'PROCESSED'),引发 buffer busy waits 或 ITL 争用。
- 每个 chunk 的执行过程必须是自治事务(
AUTONOMOUS_TRANSACTION),独立提交,不可依赖外层事务 - 禁止在 chunk 过程里做
SELECT ... FOR UPDATE,改用MERGE或带WHERE CURRENT OF的游标更新 - 如果更新涉及关联子查询,子查询必须走索引,否则每个 chunk 都会触发全表扫描
为什么 DBA_TAB_MODIFICATIONS 里看不到更新记录?
因为 DBMS_PARALLEL_EXECUTE 底层用的是普通 DML(哪怕开了 ALTER SESSION ENABLE PARALLEL DML),不是直接的并行 DML 语句,所以不会触发统计延迟刷新机制。
更麻烦的是:如果你依赖 DBA_TAB_MODIFICATIONS 做增量同步判断,这里的数据就不可信了。
- 监控真实进度,应查
user_parallel_execute_tasks的status和processed_rows - 更新完成后手动
DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO,否则STALE状态可能卡住几小时 - 别在 chunk 过程里调
COMMIT太频繁(如每 100 行一次),会导致 undo segment 争用,建议每 chunk 一次提交
真正难的不是启动并行,而是让每个 chunk 的 SQL 在高并发下依然稳定走索引、不放大逻辑读、不意外锁表——这些细节藏在你的 WHERE 条件和执行计划里,不在包文档里。

















