Oracle 19c未新增PL/SQL集合语法,其优化聚焦于BULK COLLECT与FORALL稳定性提升、DBMS_SQL批量绑定改进及统计信息协同优化;关键需更新统计信息并配置直方图以保障执行计划准确。
oracle 19c 对 pl/sql 集合(pl/sql collection)本身没有新增语法或类型,所谓“新特性优化”实际是指利用 19c 中更成熟的底层机制(如 bulk collect 与 forall 的稳定性增强、dbms_sql 批量绑定改进、以及统计信息与执行计划协同优化能力)来规避旧版本中常见的集合处理性能陷阱。
为什么 19c 的 BULK COLLECT 更稳,但默认行为没变
19c 并未修改 BULK COLLECT 的语法或默认限制,但它修复了若干 RAC 环境下因游标缓存不一致导致的批量获取中断问题;更重要的是,19c 优化器对 WHERE 条件中含集合变量(如 IN (SELECT * FROM TABLE(my_array)))的估算更准——前提是该集合对应的基础表统计信息已更新且带直方图。
- 若你仍用
BULK COLLECT INTO my_tab LIMIT 1000却发现每次 fetch 耗时波动大,先查V$SQL_PLAN是否出现NESTED LOOPS回退到单行驱动:这往往是因为关联字段缺失直方图,让优化器误判集合大小为 1 - 19c 默认启用
_optimizer_use_feedback=FALSE(关闭自适应计划反馈),反而有利于稳定批量路径;若手动开启,可能因首次执行采样偏差导致后续批量计划被回退 - 不要依赖
my_tab.COUNT做循环判断后立刻FORALL:19c 中若该集合来自BULK COLLECT且源 SQL 含绑定变量,而变量值导致结果集为空,my_tab是NULL而非空集合,直接FORALL会报ORA-06531: Reference to uninitialized collection
FORALL 的 SAVE EXCEPTIONS 在 19c 中的真实开销
19c 没有降低 SAVE EXCEPTIONS 的内存与解析成本,它依然需要为每条失败语句维护独立错误上下文。但在高并发 RAC 场景下,19c 改进了异常堆栈捕获的线程安全性,避免了部分节点因争用 ERROR_LOG 内存结构导致的隐式串行化。
- 仅当必须逐条定位失败记录时才用
SAVE EXCEPTIONS;否则优先用FORALL i IN INDICES OF my_tab+ 预校验逻辑(比如提前SELECT COUNT(*) FROM DUAL WHERE my_tab(i).status NOT IN ('A','P')) -
FORALL绑定数组长度超过 10,000 时,19c 会自动拆分为多个子批(chunk),但每个 chunk 仍需单独硬解析 —— 若你的 DML 含复杂子查询,应主动用i IN 1..5000分段控制,避免触发隐式分片带来的额外解析开销 - 别在
FORALL中混用INDICES OF和VALUES OF:19c 不报错,但执行计划可能跳变为UNION ALL多次扫描同一张表,尤其当索引列是函数索引时
用 DBMS_SQL 替代隐式游标做动态集合处理
当集合元素需参与动态 SQL 构建(例如字段名/表名来自配置表),19c 的 DBMS_SQL 新增了 BIND_ARRAY 接口支持原生数组绑定,绕过传统 EXECUTE IMMEDIATE 字符串拼接的解析瓶颈。
- 示例场景:将
my_ids(PLS_INTEGER数组)传入动态UPDATE,旧写法EXECUTE IMMEDIATE 'UPDATE t SET flag=1 WHERE id IN ('||list_to_string(my_ids)||')'在 19c 中仍会触发硬解析+SQL 注入风险;改用DBMS_SQL.BIND_ARRAY可复用同一游标,且数组长度变化不影响执行计划 -
DBMS_SQL方式要求显式定义列类型:对NUMBER字段必须用DEFINE_COLUMN指定精度,否则 19c 可能因类型推导失败回落到低效的TO_CHAR隐式转换 - 注意
DBMS_SQL游标需手动CLOSE;19c 不再自动回收长期打开的动态游标,泄漏会导致ORA-01000: maximum open cursors exceeded
真正容易被忽略的是:19c 中集合处理的性能天花板,往往卡在 SQL 层而非 PL/SQL 层——比如 BULK COLLECT 拿到 10 万行后做内存排序,耗时可能只占 5%,但前面那条 SELECT /*+ PARALLEL(4) */ 若因统计信息陈旧选错执行计划,就占了 90%。所以任何集合优化动作前,先确认 dba_tab_statistics 的 last_analyzed 是今天,且关键字段直方图不是 NONE。











