MINUS是比对物化视图与基表行级差异最准、最轻量的初筛手段,需字段名、顺序、类型严格一致,注意聚合粒度匹配、NULL语义及FAST刷新状态。

直接比对物化视图和基表的行级差异
别依赖肉眼扫两遍结果,用 MINUS 做集合差是最准、最轻量的初筛手段。它能立刻告诉你“哪些行在物化视图里有、基表里没有”,反之亦然。
- 必须显式写出字段名,且顺序、类型完全一致;
*容易因视图字段顺序变动导致误报 - 物化视图若含聚合(如
AVG()、COUNT()),需先确认其GROUP BY粒度与基表逻辑匹配,否则MINUS会把合法聚合结果判为“不一致” - 注意
NULL处理:Oracle 的MINUS把两个NULL视为相等,这点和=语义一致,不用额外转换 - 示例:
(SELECT id, score_80_90_avg FROM mv_score) MINUS (SELECT id, AVG(score_80_90) FROM base_table GROUP BY id)
检查物化视图是否还在走 FAST 刷新
一旦 CAN_USE_LOG = 'NO',说明物化视图已退化为全量刷新,但你可能根本没察觉——看起来“能刷”,实则每次都在重跑整个定义 SQL,中间出错或超时都可能导致静默截断。
- 查
USER_MVIEWS:SELECT CAN_USE_LOG FROM USER_MVIEWS WHERE MVIEW_NAME = 'MV_SCORE',返回NO就得立刻停用并排查日志 - 查日志表本身:
SELECT rowids, primary_key FROM DBA_MVIEW_LOGS WHERE master = 'BASE_TABLE',二者都为'N'时,FAST 刷新能力已彻底失效 - 日志表若被
TRUNCATE或OBJECT_ID不匹配(dba_mview_logs.master_object_id ≠ dba_objects.object_id),即使rowids = 'Y'也无效
验证物化视图定义中的表达式是否产生隐式截断
AVG() 是高频雷区:基表该列有值,物化视图却返回 NULL,大概率不是数据丢了,而是 Oracle 在物化视图构建阶段对空值聚合做了更严格的判定,和你在普通查询里看到的行为不一致。
- 把视图定义里的聚合表达式单独拎出来,在基表上重跑:
SELECT AVG(score_80_90), SUM(score_80_90)/NULLIF(COUNT(score_80_90), 0) FROM base_table,对比两者是否真不同 - 字段精度变更常被忽略:基表改了
NUMBER(10,2)→NUMBER(12,4),但物化视图对应列仍是旧精度,会导致计算溢出后变NULL;用ALTER TABLE mv_score MODIFY (score_80_90_avg NUMBER(12,4))对齐 - 自定义函数或类型方法更新后,必须确认
ALL_SOURCE中的TYPE BODY和当前ALTER TYPE语句完全一致,否则物化视图可能缓存旧返回逻辑
排除“假不一致”:确认你查的真是同一份快照
最容易白忙活的坑:你在从库查物化视图,主库刚刷完但 DG 延迟还没追上;或者你查的是普通视图 v_score,而对比的是未刷新的物化视图 mv_score——前者每次执行都重算,后者只在刷新时刻固化。
- 查延迟:
SELECT VALUE FROM V$DATAGUARD_STATS WHERE NAME = 'apply lag',单位是秒,大于 0 就说明从库数据滞后 - 确认刷新状态:
SELECT LAST_REFRESH_DATE, REFRESH_MODE FROM USER_MVIEWS WHERE MVIEW_NAME = 'MV_SCORE',ON DEMAND类型必须手动DBMS_MVIEW.REFRESH('MV_SCORE')才会更新 - 非确定性函数如
SYSDATE、ROWNUM、DBTIMEZONE会让物化视图每次刷新结果浮动,这类物化视图本质上就不适合做“精确比对”
FUNCTION 在编译时悄悄用了旧版本符号。这些不会报错,只会让数据慢慢偏移。


















