物化视图统计信息过期导致分区裁剪失效,因优化器误判其为非分区表;需查DBA_TAB_STATISTICS中PARTITIONED='NO'、LAST_ANALYZED陈旧及执行计划无PARTITION_RANGE,且必须显式对物化视图或预建表名收集统计信息。

物化视图统计信息过期导致分区消除失效的直接原因
因为优化器根本“看不见”物化视图的分区结构——DBA_TAB_STATISTICS里NUM_ROWS、AVG_ROW_LEN、GLOBAL_STATS等字段失真,导致它误判物化视图是单段表(non-partitioned),连PARTITION RANGE都不会出现在执行计划里,更谈不上裁剪。
怎么确认是不是统计信息问题而非分区定义错误
别急着改DDL,先查三处关键证据:
- 执行
SELECT LAST_ANALYZED, NUM_ROWS, PARTITIONED FROM DBA_TAB_STATISTICS WHERE TABLE_NAME = 'MV_SALES_MONTHLY':如果LAST_ANALYZED远早于最近一次刷新时间,且PARTITIONED = 'NO',就是统计没更新,不是分区没建好 - 跑
EXPLAIN PLAN FOR SELECT * FROM MV_SALES_MONTHLY WHERE sales_month = '2024-01',再SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY):看OBJECT_NAME列是否为物化视图名,以及PARTITION_START/PARTITION_STOP是否显示KEY(表示未识别分区)或具体分区号(如3) - 对比
DBA_TAB_PARTITIONS和DBA_TAB_STATISTICS:前者有分区记录,后者PARTITIONED = 'NO',说明统计信息压根没采集到分区元数据
为什么只收集基表统计信息完全无效
物化视图是独立段(segment),优化器访问它时,只查DBA_TAB_STATISTICS中对应物化视图名(或预建表名)的记录,基表统计信息对它零影响。哪怕基表有完美索引+最新统计,只要物化视图自己的LAST_ANALYZED是空或陈旧,执行计划就必然走歪。
常见错觉是:“我刚对基表跑了DBMS_STATS.GATHER_TABLE_STATS,MV应该也生效了”——实际完全不生效。必须显式对物化视图名(或ON PREBUILT TABLE指定的物理表名)执行统计收集。
刷新后必须立刻收集统计信息的关键操作
不能等自动任务,也不能依赖夜间作业。刷新完成即刻执行:
- 用
DBMS_STATS.GATHER_TABLE_STATS目标必须是物化视图名(如'MV_SALES_MONTHLY')或预建表名,不是基表名 - 务必加
cascade => TRUE,否则本地索引统计不更新,索引可能被忽略 - 避免
estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE:对大分区物化视图,这会导致采样耗时数小时;设为10或20更可控 -
method_opt别用'FOR ALL COLUMNS SIZE AUTO':对物化视图这种结构固定对象,应指定关键过滤列,例如'FOR COLUMNS SIZE 254 SALES_MONTH, CUSTOMER_ID'
最隐蔽的坑是:物化视图建在预建表上时,统计信息必须收集到那个物理表名上,而不是物化视图名——否则DBA_TAB_STATISTICS里压根查不到对应记录。


















