oracle 12c在线统计不收集分区级统计,因其仅覆盖全局和列级基础统计,缺失各分区的num_rows等关键指标,导致优化器在分区裁剪时基数估算严重失准;必须手动调用gather_table_stats并显式指定partname、method_opt等参数补全。
直接路径批量加载后,分区表的分区级统计信息不会自动更新,必须手动触发 dbms_stats.gather_table_stats 并显式指定 partname,否则优化器在 where partition_key = :val 场景下极易选错执行计划。
为什么不能只靠在线统计自动覆盖分区级统计
Oracle 12c 的在线统计(Online Statistics Gathering)仅在两个条件同时满足时触发:表初始为空 + 使用直接路径插入(如 INSERT /*+ APPEND */ 或 CREATE TABLE AS SELECT)。即便触发,它也只收集全局(GLOBAL)和列级基础统计,完全跳过每个分区的 NUM_ROWS、BLOCKS、AVG_ROW_LEN 等关键指标。这些缺失值会导致优化器误判分区剪枝效果,尤其在时间范围裁剪类查询中表现明显。
手动收集单个分区的正确调用方式
必须显式传入大小写敏感的 partname,且所有对象名默认为大写(除非建表时用双引号定义):
-
ownname和tabname必须大写,否则报ORA-20000: Unable to get table statistics -
partname必须与DBA_TAB_PARTITIONS.PARTITION_NAME完全一致(含大小写),建议先查该视图确认 - 省略
degree会退化为串行;大数据量分区建议设为DBMS_STATS.AUTO_DEGREE或具体数值(如4) - 若需直方图,必须显式指定
method_opt,例如'FOR ALL COLUMNS SIZE SKEWONLY';默认不生成直方图
示例(收集 SH.SALES 表的 P2023_Q4 分区):
EXEC DBMS_STATS.GATHER_TABLE_STATS( ownname => 'SH', tabname => 'SALES', partname => 'P2023_Q4', degree => 4, method_opt => 'FOR ALL COLUMNS SIZE SKEWONLY', cascade => FALSE );
批量收集多个分区时的并发陷阱
即使开启全局并发(CONCURRENT='ALL'),GATHER_TABLE_STATS 对同一张分区表的多个分区仍强制串行执行——Oracle 内部会锁住整张表,逐个分区处理:
- 用循环遍历
DBA_TAB_PARTITIONS调用多次,不会真正并发 - 想提速,得把不同表的分区拆到不同 job 中(例如
SALES.P1和CUSTOMERS.P1可并行) - 盲目提高
JOB_QUEUE_PROCESSES反而可能因资源争用拖慢整体耗时 - 更稳妥做法:先筛选
STALE_STATS = 'YES'的分区,再按表分组,每组单独发起一次带partname的调用
直方图与索引统计必须单独处理
INCREMENTAL 模式只影响基础统计(NUM_ROWS、AVG_ROW_LEN等),但以下两类统计不会自动继承到分区级:
- 直方图:必须显式设置
GRANULARITY => 'AUTO'并搭配METHOD_OPT(如'FOR ALL COLUMNS SIZE AUTO'),否则每个分区无独立直方图 - 索引统计:默认不按分区收集;只有 LOCAL 分区索引,且调用
DBMS_STATS.GATHER_INDEX_STATS时传入GRANULARITY => 'ALL'才生效 - 常见症状:
EXPLAIN PLAN显示分区裁剪正确,但连接顺序错误——大概率是连接列缺少分区级直方图,导致基数估算偏差超 10 倍
最易被忽略的是:活跃分区(如当前月分区)一旦锁住统计,后续数据变更就不再反映在统计中,而 STALE_STATS 标记也不会更新,这个状态需要人工持续核对。











