全量刷新适合基表更新极少、查询逻辑复杂(含聚合/窗口函数等)、数据量小(百万行内)、无法预建日志或唯一索引的场景。

全量刷新适合什么场景
全量刷新就是重新执行一遍物化视图的 SELECT 语句,把结果全量覆盖旧数据。它不依赖额外结构,只要基表列类型和物化视图定义列匹配,就能跑通。
适合这些情况:
- 基表更新极少(比如配置表、维度表每月只改几次)
- 物化视图查询逻辑复杂,含
MAX/MIN、ORDER BY、窗口函数、子查询或DISTINCT—— 这些基本不支持增量刷新 - 数据量不大(
100 万行以下),全量执行秒级完成 - 你无法控制基表变更节奏,也没法提前建好物化视图日志(
MLOG$)或唯一索引
注意:OceanBase 全量刷新会创建隐藏表再切换,需要临时双倍存储空间;PostgreSQL 的 REFRESH MATERIALIZED VIEW(无 CONCURRENTLY)会锁住视图读取,期间查询阻塞。
增量刷新失败的常见原因
所谓“增量刷新”,不是数据库自动识别哪几行变了,而是靠显式机制对齐变更范围。不同数据库报错表现不同,但根因高度一致。
典型失败点:
- Oracle:没提前建
MATERIALIZED VIEW LOG,或日志里缺了物化视图SELECT中用到的列 —— 查USER_MVIEW_LOGS就能确认 - PostgreSQL:
REFRESH MATERIALIZED VIEW CONCURRENTLY报错cannot refresh materialized view "xxx" concurrently because it does not have a unique index,说明物化视图上没建UNIQUE索引,或者索引没覆盖所有输出列 - ClickHouse:物化视图没触发,大概率是写入没走定义里的源表(比如往
Distributed表批量导入,而不是直接INSERT INTO source_table) - MySQL/OceanBase:聚合语句用了
MAX/MIN或HAVING,直接被判定不支持增量,DBMS_MVIEW.EXPLAIN_MVIEW会显示REFRESH_METHOD = 'COMPLETE'
怎么判断当前物化视图实际走的是哪种刷新
别信文档写的 FAST 或 CONCURRENTLY,得看执行时的真实行为。
关键动作:
- Oracle:运行
EXEC DBMS_MVIEW.EXPLAIN_MVIEW('your_mv'),查MV_CAPABILITIES_TABLE表,重点看REFRESH_METHOD(FAST/COMPLETE)和REFRESH_STATUS(DISABLED表示不可增量) - PostgreSQL:用
EXPLAIN (ANALYZE, BUFFERS)包裹REFRESH MATERIALIZED VIEW CONCURRENTLY mv_name,观察是否扫描了全量基表 —— 如果Rows Removed by Filter几乎为 0,说明仍是全量计算+upsert合并 - OceanBase:执行
DBMS_MVIEW.REFRESH时加atomic_refresh => FALSE参数可跳过异地刷新校验,但不会改变刷新本质;真正要看日志里有没有fast refresh字样
很多团队以为开了 FAST 就省资源,结果发现 CPU 和 IO 毫无下降 —— 很可能只是名字叫增量,实际还是全量算完再比对。
调度刷新时容易忽略的权限与路径细节
自动刷新不是配个 cron 就完事,数据库内核级调度有隐性约束。
实操要点:
- pg_cron 调度 PostgreSQL 物化视图,必须确保
cronschema 对目标用户授权:GRANT USAGE ON SCHEMA cron TO your_user,否则任务静默失败 - OceanBase 定时刷新用
START WITH ... NEXT,但NEXT表达式不支持函数(如NEXT SYSDATE + 1/24合法,NEXT DATE_ADD(NOW(), INTERVAL 1 HOUR)会报错) - 跨库刷新时,PostgreSQL 的 pg_cron 默认在
postgres库运行,物化视图在app_db库就得写成app_db.public.mv_summary;Oracle 的DBMS_SCHEDULER则需显式指定schema参数 - 避免用
FORCE刷新模式 —— 它看似智能,实则掩盖问题:当增量条件不满足时自动退化为全量,但你不报警也看不到,直到某次刷新卡住 20 分钟才发现
真正稳定的策略,是把刷新方式、触发时机、失败重试全部显式拆开控制,而不是依赖数据库的“自动兜底”。

















