Oracle 19C执行dbms_stats.gather_table_stats慢报ORA-00904错误咨询
问题场景
Oracle 19C环境执行如下统计信息收集语句时遇到两类异常:dbms_stats.gather_table_stats(ownname =>'xx', tabname =>'yyy', cascade=>true, no_invalidate=>false);
- 数据量约8000万行的目标表收集速度过慢
- 部分表执行收集时返回错误
ORA-00904 : invalid identifier
ORA-00904 排查与修复方案
按优先级从高到低排查:
- 校验对象名匹配性:Oracle默认数据字典中存储的用户名、表名为全大写,如果建表时用双引号指定了带小写、特殊字符的对象名,直接传入常规字符串会匹配失败报标识符错误。先执行
select owner, table_name from dba_tables where table_name like '%YYY%'拿到数据字典中存储的精确对象名,替换传入参数即可。 - 排查表关联的失效对象:统计信息收集会解析表上所有虚拟列、函数索引、触发器的定义,如果这些对象引用了已删除的列、不存在的自定义函数,就会抛出904错误。可以先执行
select column_name, data_default from dba_tab_cols where owner='对应大写用户名' and table_name='对应大写表名' and virtual_column='YES'检查虚拟列定义,再查dba_indexes中该表的函数索引定义,定位到引用不存在标识符的对象后,删除或重建对应对象即可。 - 规避版本bug:19C早期未打RU补丁的版本存在内部解析缺陷,收集带隐藏列、JSON列、扩展统计信息的表时会误报904,将数据库升级到19.10及以上版本的稳定RU即可修复这类问题。
8000万行级大表收集速度优化方案
- 开启并行收集:在收集语句中添加
degree=>DBMS_STATS.AUTO_DEGREE参数,Oracle会根据服务器CPU配置、表大小自动分配并行进程,通常可将单表收集耗时压缩到串行执行的1/5~1/8,注意并行度不要设置超过服务器物理CPU核数的2倍,避免抢占业务资源。 - 开启增量统计信息(针对分区表):如果目标表是分区表,先执行
dbms_stats.set_table_prefs('XX','YYY','INCREMENTAL','TRUE')开启增量收集,后续收集时只会扫描数据发生变更的分区,不需要全量扫描全表所有分区,亿级分区表场景下收集速度可提升一个数量级。 - 调整采样与收集范围:默认的
AUTO_SAMPLE_SIZE采样策略已经做过性能优化,不建议盲目调低采样率影响统计信息精度;如果表上字段数据分布均匀,不需要对所有字段生成直方图,可以设置method_opt=>'FOR ALL COLUMNS SIZE AUTO'让Oracle自动选择需要生成直方图的字段,减少不必要的计算开销。cascade=>true会同时收集表上所有索引的统计信息,如果存在大量废弃无用索引,先清理再执行收集能明显缩短耗时。 - 降低收集时的业务负载影响:当前参数
no_invalidate=>false会在统计信息收集完成后立即失效所有依赖该表的SQL游标,触发大量硬解析,推高数据库整体负载,间接拖慢收集速度。非紧急上线场景可以将该参数改为no_invalidate=>DBMS_STATS.AUTO_INVALIDATE,让游标在后续几小时内逐步失效,避免瞬时负载峰值。
快速验证流程
- 对报904错误的表,先执行
select * from xx.yyy where rownum=1确认表本身可正常访问,排除权限、对象丢失问题 - 去掉
cascade=>true参数单独收集表级统计信息,如果不再报错,说明问题出在表上的索引、触发器等关联对象,逐个排查即可 - 大表收集前先在测试环境验证并行、增量参数的收集效果,确认耗时和统计信息精度符合预期后再在生产环境执行
内容的提问来源于stack exchange,提问作者user4935529
相关产品推荐
相关产品推荐

