非分区表的update /+ parallel /静默失效,因oracle原生并行dml仅支持分区表;非分区表缺乏天然数据边界,优化器不启动px进程,v$px_session为空且执行计划无parallel操作符。

非分区表的 UPDATE /*+ PARALLEL */ 会静默失效,必须用 DBMS_PARALLEL_EXECUTE 手动切块 + 动态 SQL 才能真正并行。
为什么直接加 PARALLEL 提示没用?
Oracle 的原生并行 DML(如 UPDATE /*+ PARALLEL(t,4) */)只对分区表生效。非分区表缺乏天然的数据边界,优化器不会启动 PX 进程——查 v$px_session 是空的,EXPLAIN PLAN 里也看不到 UPDATE (PARALLEL) 操作符。这不是 bug,是设计限制。
常见错误现象:
- 语句执行时间跟串行一样,但不报错
- 锁住整张表,而不是局部行段
- 事务回滚段暴涨,甚至触发 ORA-01555
CREATE_CHUNKS_BY_ROWID 是最稳妥的切块方式
按物理存储位置(ROWID)切块,不依赖业务字段、不扫描全表统计、执行计划稳定,适合绝大多数场景。
使用前提与注意点:
- 表不能是索引组织表(IOT)或临时表,否则报错
ORA-29400: data cartridge error CHUNKING BY ROWID NOT SUPPORTED FOR THIS TABLE TYPE -
CHUNK_SIZE建议设为 5000–50000 行:太小导致调度开销占比高;太大则单 chunk 失败时重试成本高 - 执行前确认
job_queue_processes > 0(常见设为 1000),否则任务创建成功但永远不触发执行 - 切块后立刻查
dba_parallel_execute_chunks,确认STATUS = 'ASSIGNED'且CHUNK_ID连续无空缺
RUN_TASK 必须拼接动态 SQL,不能直接调用存储过程
RUN_TASK 不是执行任意 PL/SQL 块,而是以每个 chunk 为单位,拼接并执行一条动态 SQL。这条 SQL 必须满足:
- 能独立完成该 chunk 的全部逻辑(例如带
:start_rowid和:end_rowid绑定变量的UPDATE) - 不能含 DDL、
COMMIT/ROLLBACK(每个 chunk 自动提交) - 必须封装成带
ROWID范围参数的过程,再在动态块中调用,例如:EXECUTE IMMEDIATE 'BEGIN my_update_proc(:1, :2); END;' USING start_rid, end_rid;
典型错误写法:sql_stmt => 'BEGIN my_proc; END;' —— 这样会作用于全表,失去 chunk 隔离性。
容易被忽略的权限和运行时陷阱
权限缺失常导致任务“创建成功但执行无声失败”:
- 需要
CREATE JOB权限(不是CREATE PROCEDURE) - 目标表上要有
UPDATE权限,且不能是只读表空间 - 如果用
BY_NUMBER_COL切块,对应列必须有索引,否则 FTS 全扫一个 chunk 就比串行还慢 - chunk 执行失败后状态变成
PROCESSED_WITH_ERROR,但任务整体状态仍可能是FINISHED,必须手动查dba_parallel_execute_chunks确认每个 chunk 的STATUS和ERROR_MESSAGE
真正麻烦的从来不是怎么写,而是怎么验证每一块都跑对了、没漏数据、没重复更新——别跳过检查 CHUNK_ID 连续性和 ERROR_MESSAGE 字段。











