物化视图刷新后查询变慢,八成是因为统计信息未更新——它不随数据自动刷新,导致优化器生成错误执行计划,如全表扫描、分区全扫、行数估算严重偏差;刷新后须立即对物化视图名(或预建表名)执行dbms_stats.gather_table_stats并指定cascade=>true、合理estimate_percent和精准method_opt。
物化视图刷新后查询变慢,八成是因为统计信息没更新——它不会随数据自动刷新,优化器仍按旧数据量和分布做执行计划,结果该走索引的走了全表扫描,该分区裁剪的扫了全部分区。
物化视图统计信息不更新的典型表现
常见错误现象:DBA_TAB_STATISTICS 中物化视图对应记录的 LAST_ANALYZED 时间远早于最近一次刷新时间;执行 EXPLAIN PLAN 发现 PARTITION RANGE ALL 而非 PARTITION RANGE SINGLE;ROWS 估算值明显偏离实际(比如显示 1 行,但实际返回 50 万行)。
- 物化视图刷新只是改数据,不触发统计信息收集,哪怕基表刚
DBMS_STATS.GATHER_TABLE_STATS过也无效 -
DBA_TAB_STATISTICS和USER_TAB_STATISTICS是唯一直观确认入口,别只看基表或日志表 - 如果物化视图建在预建表(
ON PREBUILT TABLE)上,统计信息必须显式收集到那个物理表名上,不是物化视图名
刷新后必须立即执行的统计收集操作
不能等夜间作业,也不能依赖自动任务——刷新完成即刻收集,否则下一条查询就可能走歪。
- 用
DBMS_STATS.GATHER_TABLE_STATS直接对物化视图名(或预建表名)执行,例如:DBMS_STATS.GATHER_TABLE_STATS('SCHEMA_NAME', 'MV_SALES_MONTHLY') - 务必加
cascade => TRUE,确保关联的本地索引统计一并更新,否则索引可能被忽略 - 若物化视图含大量分区,避免默认
estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE导致耗时过长,可设为10或20平衡精度与速度 - 不要用
method_opt => 'FOR ALL COLUMNS SIZE AUTO',对物化视图这种结构固定、过滤列明确的对象,应指定关键列:method_opt => 'FOR COLUMNS SIZE 254 CUSTOMER_ID, SALES_MONTH'
为什么只收集基表统计信息没用
物化视图是独立段(segment),优化器查它时完全不参考基表统计。即使基表有完美索引和最新统计,物化视图本身统计陈旧,执行计划照样错。
- 执行
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY)后看OBJECT_NAME列,确认 Plan 中访问的是MV_SALES_MONTHLY而非基表名 -
DBA_MVIEWS.STALENESS = 'FRESH'只表示数据同步,不代表统计可用;STALENESS = 'STALE'时甚至可能跳过查询重写,直接走基表 - 如果物化视图启用了
QUERY REWRITE,但统计未更新,优化器可能因成本误判而放弃重写,转而执行原始复杂 SQL
统计信息滞后是隐形瓶颈,不报错、不告警,只让查询越来越卡。每次 DBMS_MVIEW.REFRESH 后加一行 DBMS_STATS.GATHER_TABLE_STATS,比事后花半天分析执行计划更省事。











