联系我们
18591797788
hubin@rlctech.com
北京市海淀区中关村南大街乙12号院天作国际B座1708室
18681942657
lvyuan@rlctech.com
上海市浦东新区商城路660号乐凯大厦26c-1
18049488781
xieyi@rlctech.com
广州市越秀区东风东路华宫大厦808号1608房
029-81109312
service@rlctech.com
西安市高新区天谷七路996号西安国家数字出版基地C座501
物化视图(Materialized View,以下简称 MV)是数据库中一种将查询结果物理持久化的对象。与普通视图仅存储 SQL 定义不同,MV 将查询执行后的结果数据真正写入磁盘——查询时可直接读取这份数据,而不必重新执行复杂的 JOIN 和聚合运算。这种"以空间换时间"的策略带来显著的性能收益,但同时也伴随着存储开销和刷新维护成本。
在实际业务中,技术团队经常面临以下决策问题:
本文针对上述问题给出个人学习总结,帮助您独立判断业务场景是否适合 MV,如何根据业务场景选择数据刷新策略、数据刷新方式等等。下文若无特殊说明,相关SQL 语句均在 4.4.2.2 环境测试过,但需要注意的是OceanBase的物化视图功能也是在不断迭代和增强功能,个人总结难免有不足或者欠缺的地方,建议以相关的官网文档指引为准,相关语句仅供参考。
判断一个业务场景是否适合使用 MV,本质上需要从"查询特征"和"数据特征"两个维度出发,评估"以空间换时间"后系统是否能达到平衡或正收益。下面提供一个 3问 + 3评估 的方法供参考,具体的场景建议结合业务数据测试验证为准。
MV 的核心价值在于"一次计算,多次复用"。如果某个查询只是偶尔执行一次(如临时数据探查、随机明细点查),为其创建 MV 的维护成本远大于查询加速收益,不建议使用。
| 适合信号 | 不适合信号 |
|---|---|
| 查询被周期性调度执行(如每小时/每天报表)、被多个应用模块反复调用、查询结果在一段时间内被大量复用。这类场景下,MV 将昂贵的计算前置到低峰期执行,高峰期直接读取预计算结果,投资回报率高。 | 一次性查询、临时分析、Ad-hoc 即席查询。这类场景查询模式不固定,MV 的预计算结果难以复用,且频繁的 DDL 变更 MV 定义会带来额外管理负担。 |
MV 的缓存价值与查询本身的计算复杂度正相关。查询越复杂——涉及多张大表的 JOIN、多层嵌套聚合、全表扫描——MV 带来的加速效果越显著。
| 适合信号 | 不适合信号 |
|---|---|
| 多表 JOIN + 聚合:每次执行需扫描多张大表并做 Hash/Merge Join,CPU 和 IO 开销大。MV 可将这部分计算前置到刷新时段,查询时仅扫描预计算结果集,收益明显。尤其当 JOIN 涉及的事实表达到千万级以上时,MV 可将分钟级查询缩短到毫秒级。 | 数据量极小(几千行以内): 全表扫描本身就很快,MV 的额外维护开销(存储空间 + 刷新资源消耗)不值得。建议优先考虑普通索引或普通视图。 对于单表明细查询: 如果只是按主键点查或简单范围扫描,普通索引已足够提供毫秒级响应,不需要 MV。MV 更适合聚合类查询而非明细检索。 |
4.4.2版本OceanBase对于物化视图数据的刷新不支持ON COMMIT 和 ON STATEMENT 刷新模式,所有 MV 的刷新均需通过 ON DEMAND 方式触发,也就是MV 数据不会随基表 DML 提交自动同步,业务必须能接受一定程度的延迟。
实际上无论ON COMMIT 、ON STATEMENT 还是通过 ON DEMAND 方式触发MV数据刷新,其基表的变更频率直接决定了 MV 的刷新成本,基表数据变更频率是选择物化视图技术时候不可避免需要考虑的一个重要因素。
考虑这个因素问题的关键在于把握一个核心比率:变更数据量与基表总数据量的比值。当这个比值很低(如每天仅变更 1%~5%),增量刷新的代价远低于全量刷新,性价比极高;但当这个比值接近 100%(如基表被频繁全量 DELETE + INSERT 轮换),增量刷新需要处理的变更数据量几乎等同于全表数据,增量优势消失,甚至因为增量合并逻辑本身的额外开销而比直接全量刷新更慢。基表变更频率不仅决定了刷新成本的高低,更决定了增量刷新这一关键策略是否可行。评估时建议重点关注的两个维度:
| 变更频率 | 变更占比 |
|---|---|
| 基表每天发生多少次 DML?是秒级高频、分钟级中频、还是天级低频?频率越高,刷新窗口越紧,对刷新策略的约束越大。 | 每次变更涉及的数据量占基表总量的比例是多少?即使基表有千万行数据,如果每天只有 1% 的行被修改,增量刷新仍然高效;反之,若每天全量替换,增量刷新就失去意义 |
特别需要注意的是: 当基表采用“批量 DELETE + INSERT 轮换”模式(即每天先删除全部旧数据再写入新数据)时,MLOG 捕获的变更记录量接近全表数据量。此时即使基表变更频率很低(每天只有一次),增量刷新的实际处理量也等同于全表扫描,优势完全消失。对于这类场景,应直接选择全量刷新,或重新评估 MV 是否仍然适用——如果基表每天都在全量替换,或许应考虑用普通表 + 定时 ETL 替代 MV。下面抽取总结了几种典型业务的基本变化场景,对于频繁全量更新/删除的场景需要慎重评估的。
| 基表变化特征 | 典型业务场景 |
|---|---|
| 极低频(几乎不写) | 历史归档表、配置字典表 |
| 低频(如每天批量导入一次) | T+1 报表、日终结算 |
| 中频(每天变更 1%~5% 的数据) | 电商订单、用户行为日志 |
| 极高频(每秒大量写入) | 实时监控、运营大屏 |
| 频繁全量更新/删除 | 批量轮换表、TRUNCATE+INSERT 模式 |
数据新鲜度从一定程度上来讲可以认为是基表数据变更频率快慢的时候业务角度需要评估因素,业务侧是否接受结果延迟,延迟的容忍度是多少?关注的评估项有如下:
| 评估项 | 判定指引 |
|---|---|
| 业务能接受数据延迟吗? | 能 → 下一项;不能(要求事务提交即同步)→ 需替代方案(见下方表格) |
| 延迟容忍度是多少? | 秒级 → ENABLE ON QUERY COMPUTATION; 分钟级 → FAST 刷新 + START WITH...NEXT;小时/天级 → COMPLETE 刷新 + 定时调度;不需更新 → NEVER REFRESH |
| 如果要求“实时”,是查询侧还是写入侧? | 查询侧(查询时看到最新数据即可)→ ON QUERY COMPUTATION 可实时性在读取侧实现,不阻塞 DML,但是采用实时物化视图,复杂性问题并不会少其实,建议多测试验证;写入侧(事务提交时刻 MV 已物理更新)→ 超出当前版本能力,需替代方案 |
ON COMMIT 不可用时建议考虑其他替代方案:
| 方案 | 原理 | 优点 | 代价 |
|---|---|---|---|
| 应用层双写 | 在应用事务中同时写入基表和汇总表 | 数据强一致,同事务提交 | 侵入业务代码,汇总逻辑在应用层实现 |
| 定时 ETL + MV | 接受分钟级延迟,FAST 刷新 + 高频调度逼近实时 | OceanBase 原生支持,无需额外基础设施 | 存在延迟窗口 |
| CDC 订阅 + 下游汇总 | 通过 obcdc 订阅基表变更,下游实时计算汇总 | 适合跨系统数据同步 | 架构复杂度高,需维护 CDC 链路 |
引入 MV 技术后的总存储增量 = MV 容器表存储 + MV Log 表存储 + Σ(MV 索引存储)。如果不涉及增量和索引,则MV LOG 和 MV索引存储取值为0。在评估项的时候考虑以下评估项,维护复杂度方面注意是否有嵌套MV的情况。
| 评估项 | 估算公式 |
|---|---|
| MV 容器表 | 输出行数 × 单行字节数 × 压缩系数(数据特征决定,建议测试验证) |
| MV 索引 | MV行数 × 索引列宽 × 索引个数 × 索引膨胀系数。膨胀系数 可通过测试观测获得,与具体的数据特征有关; |
| MV Log 表(仅 FAST/FORCE 刷新) | 日均 DML 变更行数 × 单条 Log 字节数 × 刷新间隔天数。MLOG 是累积型的——不刷新就持续增长;INCLUDING NEW VALUES 会使列数考虑翻倍 |
| 嵌套 MV 层数 | 依赖链深度:基表→MV-B→MV-A 为 2 层。每层多一份数据 + 索引 + MLOG |
| 基表 DDL 变更频率如何? | 频繁 DDL 可能导致 MLOG 列缺失,FAST 刷新降级(FORCE 自动降 COMPLETE,FAST 直接报错) |
| 升级路径中的 MV 特性兼容性验证? | 不同版本对 MV 高级特性支持程度不同 |
OceanBase 对物化视图高级功能的支持依赖具体版本,使用前必须验证:执行 SELECT version() 确认当前OB版本,确定包括但不局限于如下的每个所需特性的支持状态,若当前版本有存在不支持的特性,若特性不支持,是否有版本升级计划?若只能通过版本升级获得,还得评估升级风险。
| 特性 | 最低支持版本 | 说明 |
|---|---|---|
| 基础 MV(COMPLETE/FAST/FORCE 刷新) | 4.3.0.0 | 核心 MV 创建与刷新能力 |
| MLOG 自动创建 | 4.3.5.4 / 4.4.2.0 | 需租户配置 enable_mlog_auto_maintenance 启用,否则需手动创建 MLOG |
| 嵌套物化视图 | 4.3.5.0 | MV 定义可引用另一个 MV |
| 级联刷新(自动刷新依赖的下层 MV) | 4.3.5.3 | 刷新父 MV 时自动刷新子 MV |
| LEFT JOIN 增量刷新 | 4.4.2.0 | 该版本支持 |
| UNION ALL 增量刷新 | 4.4.2.0 | 该版本支持 |
| REFRESH PARALLEL(并行刷新) | 4.4.2.0 | 在 REFRESH 子句中指定并行度 |
| ON QUERY COMPUTATION(实时 MV) | 4.4.2.0 | 查询时合并 MLOG,要求 MV 满足 FAST 刷新条件 |
| 查询改写(Query Rewrite) | 4.4.2.0 | 系统变量 query_rewrite_enabled 控制 |
选定 MV 方案后,接下来的聚焦问题就是进一步确定具体采用哪种刷新策略?OceanBase 4.4.2 CE 提供四种刷新策略:
| 策略 | 关键字 | 行为 | 适用场景 |
|---|---|---|---|
| 全量刷新 | COMPLETE | 每次重新执行完整查询,覆盖全部数据 | 数据量小(百万级以下)、增量刷新不满足条件、定期重建修正累积偏差 |
| 增量刷新 | FAST | 只处理自上次刷新以来的变更数据 | 数据量大(千万级以上)、变更频繁但每次变更比例不高、查询满足增量条件 |
| 混合刷新 | FORCE | 先尝试增量,失败则回退全量 | 不确定是否满足增量条件,希望系统自动判断 |
| 永不刷新 | NEVER REFRESH | 仅创建时填充一次,之后不再刷新 | 静态数据、历史快照、只读报表 |
适用条件: 当基表数据量不大(百万行以内),全量重算的成本可以接受;或者 MV 的查询语句不满足增量刷新的条件(如包含 DISTINCT、窗口函数等),只能选择全量刷新。此外,即使在日常使用 FAST 刷新的场景下,也建议定期执行一次 COMPLETE 刷新作为兜底方案,修正增量刷新可能累积的数据偏差。
潜在代价: COMPLETE 刷新期间需要额外存储空间——系统会创建新的数据表来存储刷新结果,刷新完成后切换到新表并删除旧表,此过程类似 Online DDL 的双表切换。MV 上的索引也需要全量重建。刷新耗时与数据量成正比,对于千万级以上的大表,COMPLETE 刷新可能耗时数十分钟甚至更久。
调度限制: COMPLETE 刷新的定时调度有最小间隔限制(默认 600 秒,由租户配置 _mv_complete_refresh_min_interval 控制),间隔过短将报错 "the interval of complete refresh is less than the minimum interval"。
创建示例:
-- 全量刷新,手动触发
CREATE MATERIALIZED VIEW mv_daily_report
REFRESH COMPLETE ON DEMAND
AS
SELECT region, product, SUM(amount) AS total
FROM orders
WHERE status = 'COMPLETED'
GROUP BY region, product;
适用条件: 基表数据量大(千万级以上),数据变更频繁但每次变更的比例不高(如每天变更 1%~5%),且 MV 的查询语句满足增量刷新的条件。增量刷新只处理自上次刷新以来基表发生的变更数据(通过 MLOG 记录),避免全量重算,是大数据量场景下性价比最高的刷新方式。增量刷新支持的查询场景有:
| 场景 | 说明 |
|---|---|
| 单表非聚合 | 最基础的增量场景,MV 直接投影基表列 |
| 单表聚合 | 支持 SUM、COUNT(*) 等基本聚合函数 |
| 多表 INNER JOIN 非聚合 | 内连接物化连接视图 |
| 多表 INNER JOIN 聚合 | 内连接 + 聚合 |
| 外连接(LEFT JOIN) | 4.4.2 起新增支持 |
| 集合查询(UNION ALL) | 4.4.2 起新增支持 |
| 大合并刷新 | 依赖 OceanBase 大合并机制的刷新 |
增量刷新不支持的场景:
MLOG 自动创建机制: 在 OceanBase 4.4.2 中,当租户配置 enable_mlog_auto_maintenance 为 true 且数据版本满足要求时,创建 FAST 刷新 MV 时系统会自动为基表创建 MLOG,用户不需要手动执行 CREATE MATERIALIZED VIEW LOG。若该配置未启用,则需手动创建 MLOG,否则 FAST 刷新将因缺少 MLOG 而无法执行,系统会自动降级为 COMPLETE 刷新(对于 FORCE 策略)或直接报错(对于 FAST 策略)。
创建示例:
-- 增量刷新,手动触发(系统自动创建 MLOG)
CREATE MATERIALIZED VIEW mv_daily_dau
REFRESH FAST ON DEMAND
AS
SELECT dt, channel, COUNT(*) AS dau
FROM user_behavior
GROUP BY dt, channel;
关于 COUNT(DISTINCT) 的特别说明: 上例中使用 COUNT(*) 而非 COUNT(DISTINCT user_id)。在 FAST 刷新中,COUNT(DISTINCT ...) 不属于基本聚合函数,它通过 group recalculate 机制处理,该机制仅支持单表场景,不支持多表 JOIN、标量分组和 ON QUERY COMPUTATION。如需统计去重用户数,建议方案:(1) 先在基表或子查询中去重再聚合,使 MV 定义变为单表聚合;(2) 接受使用 COMPLETE 刷新。
适用条件: 当不确定 MV 是否满足增量刷新的条件,或查询语句可能在不同数据分布下满足/不满足增量条件时,选择 FORCE 策略。系统会自动判断:能增量就增量,不能增量就全量。即使增量失败也不会报错,自动降级为 COMPLETE,是一种"安全优先"的选择。
FORCE 策略特别适合以下场景:MV 查询语句中包含条件分支(如 CASE WHEN)导致在不同数据分布下可能满足或不满足增量条件;或者开发团队对增量刷新条件不够了解,希望系统自动决策。
创建示例:
-- 先尝试增量,失败则全量
CREATE MATERIALIZED VIEW mv_sales_summary
REFRESH FORCE ON DEMAND
AS
SELECT region, SUM(amount) AS total
FROM orders
GROUP BY region;
3.4 永不刷新(NEVER REFRESH)
适用条件: 数据是静态的,不会变化(如历史归档表、审计日志快照);或只需要创建时的一份快照作为某个固定时间点的数据切片,之后不需要更新。NEVER REFRESH 的 MV 在创建时执行一次完整查询填充数据,之后无论基表如何变更,MV 数据始终保持创建时的状态。
创建示例:
-- 只创建一次,永不刷新
CREATE MATERIALIZED VIEW mv_2024_snapshot
NEVER REFRESH
AS
SELECT * FROM orders WHERE order_date BETWEEN '2024-01-01' AND '2024-12-31';
OceanBase 4.4.2 CE 仅支持 ON DEMAND 刷新模式——刷新不会在基表 DML 提交时自动触发,需要通过以下两种方式之一主动触发。
在创建 MV 时通过 START WITH 指定首次刷新时间、NEXT 指定后续刷新间隔,系统会自动创建定时调度任务:
-- 每天自动全量刷新(1 小时后首次执行,之后每 1 天一次)
CREATE MATERIALIZED VIEW mv_daily_sales
REFRESH COMPLETE ON DEMAND
START WITH SYSDATE() + INTERVAL 1 HOUR
NEXT SYSDATE() + INTERVAL 1 DAY
AS SELECT region, SUM(amount) AS total FROM orders GROUP BY region;
-- 每 5 分钟增量刷新
CREATE MATERIALIZED VIEW mv_realtime_stats
REFRESH FAST ON DEMAND
START WITH SYSDATE() + INTERVAL 5 MINUTE
NEXT SYSDATE() + INTERVAL 5 MINUTE
AS SELECT channel, COUNT(*) AS cnt FROM orders GROUP BY channel;
OceanBase 在 MySQL 模式下提供了独立的 DBMS_MVIEW PL 系统包,通过 CALL 语法调用 REFRESH 存储过程手动触发刷新:
-- 全量刷新(method 参数使用简写 'C')
CALL DBMS_MVIEW.REFRESH('mv_daily_sales', 'C');
-- 增量刷新(method 参数使用简写 'F')
CALL DBMS_MVIEW.REFRESH('mv_realtime_stats', 'F');
-- 强制刷新——先尝试增量,失败则全量(method 参数使用 '?')
CALL DBMS_MVIEW.REFRESH('mv_sales_summary', '?');
-- 使用 MV 定义的默认刷新方法(method 传 NULL)
CALL DBMS_MVIEW.REFRESH('mv_daily_sales', NULL);
-- 指定刷新并行度(第 3 个参数)
CALL DBMS_MVIEW.REFRESH('mv_daily_sales', 'C', 4);
DBMS_MVIEW.REFRESH 完整参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
| mv_name | VARCHAR | 物化视图名称 |
| method | VARCHAR | 刷新方法简写:'C'=COMPLETE、'F'=FAST、'?'=FORCE;传 NULL 使用 MV 默认方法 |
| refresh_parallel | INT | 刷新并行度,默认 0(不指定并行) |
| nested | BOOLEAN | 是否级联刷新依赖的下层 MV,默认 FALSE |
| nested_refresh_mode | VARCHAR | 级联刷新模式(INDIVIDUAL/INCONSISTENT/CONSISTENT),默认 NULL |
| async | BOOLEAN | 是否异步刷新(TRUE 立即返回,FALSE 阻塞等待完成),默认 FALSE |
| force | BOOLEAN | 是否强制终止该 MV 的在途刷新再重新调度,默认 FALSE |
注意:method 参数必须使用简写字母('C'/'F'/'?'),不支持完整单词。传入 'COMPLETE' 将返回 "Invalid argument" 错误。这与 Oracle 模式下的行为不同——Oracle 模式接受完整单词。MySQL 模式下的正确用法是 CALL DBMS_MVIEW.REFRESH('mv_name', 'C')。
通过 oceanbase.DBA_MVIEWS 视图查询 MV 的刷新状态和数据同步延迟:
SELECT
mview_name,
refresh_method,
refresh_mode,
last_refresh_type,
last_refresh_date,
on_query_computation,
rewrite_enabled,
data_sync_delay -- 数据同步延迟(秒),反映 MV 数据与基表的时间差
FROM oceanbase.DBA_MVIEWS
WHERE mview_name = 'your_mv_name';
字段语义说明:
CREATE MATERIALIZED VIEW [IF NOT EXISTS] view_name
[ (column_list) ]
[ PRIMARY KEY(column_list) ]
[table_option_list]
[partition_option]
[mv_column_group_option]
[refresh_clause]
[query_rewrite_clause]
[on_query_computation_clause]
AS view_select_stmt;
| 子句 | 说明 | 示例 |
|---|---|---|
| view_name | 物化视图名称 | mv_sales_summary |
| column_list | 指定列名(可选,默认从 SELECT 推导) | (region, product, total) |
| PRIMARY KEY | 指定主键,优化基于主键的查询 | PRIMARY KEY(region, product) |
| table_option_list | 表选项,与普通表一致 | PARALLEL 5 |
| partition_option | 分区策略,与普通表一致 | PARTITION BY HASH(id) PARTITIONS 8 |
| mv_column_group_option | 存储格式,可指定列存 | WITH COLUMN GROUP(each column) |
| refresh_clause | 刷新策略和调度方式 | REFRESH FAST ON DEMAND |
| query_rewrite_clause | 是否开启查询改写 | ENABLE QUERY REWRITE |
| on_query_computation_clause | 是否开启实时模式 | ENABLE ON QUERY COMPUTATION |
| view_select_stmt | 定义数据的查询语句 | SELECT ... FROM ... WHERE ... |
refresh_clause:
REFRESH [COMPLETE | FAST | FORCE] [PARALLEL n] [mv_refresh_on_clause]
| NEVER REFRESH
mv_refresh_on_clause:
[ON DEMAND] [[START WITH expr] [NEXT expr]]
| 参数 | 说明 |
|---|---|
| COMPLETE | FAST |
| NEVER REFRESH | 永不刷新,与上述三种互斥 |
| PARALLEL n | 指定刷新并行度(n 为并行 worker 数,0 表示不指定) |
| ON DEMAND | 按需触发刷新(默认值) |
| START WITH expr | 首次自动刷新的时间表达式 |
| NEXT expr | 后续刷新的时间间隔表达式 |
query_rewrite_clause:
DISABLE QUERY REWRITE | ENABLE QUERY REWRITE
on_query_computation_clause:
DISABLE ON QUERY COMPUTATION | ENABLE ON QUERY COMPUTATION
查询改写(Query Rewrite)是优化器的一项高级能力:当用户查询基表时,如果存在一个数据新鲜的 MV 能够回答该查询,优化器会自动将查询改写为访问 MV,从而避免重新执行昂贵的 JOIN 和聚合运算。这一过程对应用完全透明——应用层无需修改任何 SQL 即可获得性能加速。
查询改写需要同时满足 MV 端、系统端和查询端三个层面的条件:
MV 端条件:
系统端条件 :
-- 开启查询改写(会话级)
SET query_rewrite_enabled = true;
-- 或全局开启
SET GLOBAL query_rewrite_enabled = true;
-- 强制使用查询改写(即使 MV 数据可能过期)
SET query_rewrite_enabled = 'FORCE';
-- 设置一致性检查级别
-- ENFORCED(默认):仅使用数据新鲜的 MV
-- STALE_TOLERATED:允许使用数据过期的 MV
SET query_rewrite_integrity = 'STALE_TOLERATED';
query_rewrite_enabled 接受三个值:FALSE(关闭)、TRUE(开启)、FORCE(强制)。query_rewrite_integrity 接受两个值:ENFORCED(仅使用新鲜 MV,默认)、STALE_TOLERATED(允许使用过期 MV)。
查询端条件:
-- 准备基表
CREATE TABLE test_tbl1 (col1 INT, col2 INT, col3 INT);
CREATE TABLE test_tbl2 (col1 INT, col2 INT, col3 INT);
-- 创建支持改写的 MV
CREATE MATERIALIZED VIEW mv_test_join
REFRESH COMPLETE ON DEMAND
ENABLE QUERY REWRITE
AS
SELECT t1.col1, t1.col2, t2.col3
FROM test_tbl1 t1, test_tbl2 t2
WHERE t1.col1 = t2.col1;
-- 刷新 MV(改写前需确保 MV 已刷新)
CALL DBMS_MVIEW.REFRESH('mv_test_join', 'C');
-- 开启查询改写
SET query_rewrite_enabled = true;
-- 以下查询可被改写为访问 mv_test_join
SELECT t1.col1, t1.col2, t2.col3
FROM test_tbl1 t1, test_tbl2 t2
WHERE t1.col1 = t2.col1 AND t1.col2 > 10;
-- 系统自动改写为:SELECT col1, col2, col3 FROM mv_test_join WHERE col2 > 10;
验证方法: 使用 EXPLAIN 查看执行计划,若改写成功,计划中将出现 MV 名称而非基表名称。
普通 MV 在两次刷新之间的数据是"过期"的——基表发生的 DML 变更不会立即反映到 MV 中。而开启了 ENABLE ON QUERY COMPUTATION 的实时 MV 解决了这一问题:在查询时,系统会自动将 MV 已有的持久化数据与 MLOG 中尚未刷新的增量变更进行合并计算,返回与基表一致的最新结果。
这一机制的核心逻辑是:MV 存储的是"上一次刷新时的快照数据",MLOG 存储的是"自上次刷新以来的增量变更"。实时 MV 在查询时将两者合并——相当于在查询执行时动态完成一次"增量刷新",但结果不持久化,仅在本次查询有效。
这意味着:
-- 创建实时物化视图
CREATE MATERIALIZED VIEW mv_realtime_channel_stats
REFRESH FAST ON DEMAND
ENABLE ON QUERY COMPUTATION
AS
SELECT channel, COUNT(*) AS order_count, SUM(amount) AS total_amount
FROM orders
WHERE status = 'COMPLETED'
GROUP BY channel;
-- 首次刷新(填充初始数据,后续基表变更会自动反映在查询结果中)
CALL DBMS_MVIEW.REFRESH('mv_realtime_channel_stats', 'F');
-- 此后基表写入新数据后,直接查询 MV 即可获取最新结果(无需再次刷新)
SELECT * FROM mv_realtime_channel_stats;