Oracle 19c实时统计对PL/SQL优化无直接作用,仅影响DML后SQL解析的基数估算;PL/SQL静态SQL复用游标依赖传统DBMS_STATS统计,EXECUTE IMMEDIATE动态SQL才可能间接受益。
oracle 19c 的实时统计信息收集(real-time statistics)对 pl/sql 优化几乎**没有直接作用**,它不参与 pl/sql 编译、绑定变量窥探或运行时执行计划选择——这些仍完全依赖传统 dbms_stats 收集的静态统计信息。
实时统计只影响 DML 后的查询优化器估算,不改变 PL/SQL 执行逻辑
实时统计是 Oracle 在执行 INSERT/UPDATE/DELETE 时,自动更新 DBA_TAB_STATISTICS 和 DBA_TAB_COL_STATISTICS 中部分字段(如 NUM_ROWS、NUM_DISTINCT)的轻量机制,仅用于后续 SQL 解析阶段的基数估算。PL/SQL 块内嵌的 SQL 语句是否重硬解析、是否复用游标、是否使用绑定变量,全由共享池状态和传统统计信息决定。
- 即使你刚插入 100 万行,实时统计立刻刷新了
NUM_ROWS,但 PL/SQL 中已缓存的游标不会自动失效或重生成执行计划 -
EXECUTE IMMEDIATE动态 SQL 会触发新解析,此时才可能受益于实时统计;而静态 SQL(如SELECT ... INTO)复用已有游标,完全无视实时值 - PL/SQL 函数内联、优化器转换(如谓词推入、视图合并)等行为,均基于
DBA_TAB_STATISTICS中GLOBAL_STATS = 'YES'的传统统计,而非实时字段
哪些 PL/SQL 场景可能“间接”受益?
只有当 PL/SQL 中的 SQL 语句在每次调用时都触发硬解析,且数据变更频繁到传统统计来不及更新时,实时统计才可能带来微弱改善。典型场景极少,需同时满足:
- 使用
EXECUTE IMMEDIATE+ 拼接 SQL(无绑定变量),且拼接逻辑导致每次 SQL 文本不同 - 表在 PL/SQL 运行期间被高频 DML 修改(如批处理循环中每轮 INSERT 后立即 SELECT)
- 该表未启用增量统计(
INCREMENTAL = TRUE),传统自动任务又滞后,导致NUM_ROWS严重失真 - 查询谓词高度依赖行数估算(如
WHERE ROWNUM 或连接顺序敏感的多表 JOIN)
注意:NOTES 列显示 STATS_ON_CONVENTIONAL_DML 仅表示实时统计已启用并记录过变更,不代表当前值已被优化器采纳——必须配合硬解析才生效。
别把实时统计当“自动优化开关”,它甚至不能替代一次 GATHER_TABLE_STATS
实时统计不是全量统计,它不收集直方图、不更新 CLUSTERING_FACTOR、不计算索引叶块数,更不触发表级 AVG_ROW_LEN 或列级 DENSITY。常见误操作包括:
- 看到
NOTES = 'STATS_ON_CONVENTIONAL_DML'就认为统计“已最新”,结果执行计划仍走错索引 - 禁用自动任务后依赖实时统计维持性能,导致大分区表全局
NUM_DISTINCT长期不准(实时统计用 HyperLogLog 估算,但只覆盖变更列,非全量) - 在 PL/SQL 包初始化块里调用
DBMS_STATS.LOCK_TABLE_STATS,却忘了实时统计无法被锁定——DML 仍会偷偷改写NUM_ROWS,引发计划漂移
真正该在 PL/SQL 中控制的,是传统统计的触发时机
若业务逻辑明确知道某次 DML 后统计必然失真(如 TRUNCATE + INSERT APPEND 加载千万级分区),应在 PL/SQL 中主动触发精准收集,而非等待实时或自动任务:
BEGIN EXECUTE IMMEDIATE 'TRUNCATE TABLE sales_part'; INSERT /*+ APPEND */ INTO sales_part SELECT * FROM staging_sales; COMMIT; <p>-- 关键:立刻补全统计,避免后续查询用错计划 DBMS_STATS.GATHER_TABLE_STATS( ownname => 'SH', tabname => 'SALES_PART', granularity => 'ALL', -- 必须 ALL,否则只扫新分区 method_opt => 'FOR ALL COLUMNS SIZE AUTO', degree => 4 ); END;
这里 granularity => 'ALL' 是关键——实时统计从不提供分区级摘要合成能力,只有显式 GATHER_TABLE_STATS 配合 INCREMENTAL = TRUE 才能安全更新全局统计。忽略这点,PL/SQL 再怎么“实时”,优化器看到的仍是陈旧的 GLOBAL_STATS = 'NO' 状态。


















