DBMS_PARALLEL_EXECUTE不是加速单条SQL的工具,而是将大DML拆分为多个小事务分批并行执行的机制,旨在避免锁表、回滚段溢出及全盘重跑;其核心价值在于“敢不敢跑”,而非“能不能快”。
直接说结论:dbms_parallel_execute 不是用来“加速单条 sql”的,而是把一个大 dml 拆成多个小事务、分批并行执行的机制。它解决的不是“能不能快”,而是“敢不敢跑”——避免锁表、撑爆回滚段、失败后全盘重来。
为什么不能直接用 PARELLEL 提示更新非分区表?
Oracle 的原生并行 DML(比如 UPDATE /*+ PARALLEL(t,4) */)要求目标表必须是分区表,否则优化器会静默忽略并行提示,实际仍是串行执行。这不是 bug,是设计限制:非分区表缺乏天然的、可独立锁定与提交的数据边界。
- 你执行
UPDATE /*+ PARALLEL */后查v$px_session,可能发现根本没 PX slave 被调起 -
EXPLAIN PLAN里也看不到LOAD AS SELECT或UPDATE (PARALLEL)操作符 - 真正生效的并行 DML 场景极少:仅限
INSERT /*+ APPEND */、CREATE TABLE AS SELECT、分区表上的 DML
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 执行时最容易踩的权限和语法坑
RUN_TASK 不是执行任意 PL/SQL 块,而是以每个 chunk 为单位,拼接并执行一条动态 SQL —— 这条 SQL 必须能独立完成该 chunk 的全部逻辑,且不能含 DDL、事务控制语句(COMMIT/ROLLBACK)。
- 函数体里写
COMMIT会报ORA-14551: cannot perform a DML operation inside a query - SQL 字符串中不能直接拼接变量,必须用绑定变量或通过
DBMS_PARALLEL_EXECUTE.GET_CHUNK_ROWID获取当前 chunk 范围 - 典型安全写法是封装一个带
ROWID范围参数的过程,再在sql_stmt中调用:'BEGIN serial(:start_rid, :end_rid); END;' - 需要
CREATE JOB和EXECUTE ON DBMS_SQL权限,普通开发账号常缺前者,得找 DBA 授权
失败后怎么定位和恢复?
任务失败不会自动回滚已成功 chunk,也不会中断后续 chunk —— 这正是它“可控”的核心。但这也意味着你得自己盯住状态。
- 查
dba_parallel_execute_tasks看整体状态(STATUS可能是CRITICAL、ERROR或STOPPED) - 查
dba_parallel_execute_chunks,筛选STATUS = 'PROCESSED' OR STATUS = 'ERROR',对比数量判断进度 - 对
STATUS = 'ERROR'的 chunk,查chunk_id对应的错误日志(需提前在过程里写DBMS_OUTPUT.PUT_LINE或写表) - 手动重跑失败 chunk:用
DBMS_PARALLEL_EXECUTE.RESUME_TASK,或删掉失败 chunk 后用DBMS_PARALLEL_EXECUTE.CREATE_CHUNKS_BY_ROWID补上
真正难的从来不是写完那几行 CREATE_TASK,而是想清楚 chunk 边界是否影响业务一致性、失败 chunk 是否可幂等重放、以及日志和监控是否跟得上——这些没法靠包自动解决。


















