游乐游手机版
首页/数据库/文章详情

Oracle物化视图刷新实现方式详解

时间:2026-07-20 07:01
物化视图将查询结果存为物理表,用于缓存、远程数据副本及预计算聚合。刷新方式有FAST(增量)、COMPLETE(完全)和FORCE(自动降级),刷新时机分为ONCOMMIT自动刷新和ONDEMAND手动触发,需配合物化视图日志实现快速刷新。

物化视图(MATERIALIZED VIEW)本质上是一种“有实体的查询结果快照”,它将查询结果的数据实际存储为一张物理表。与普通视图不同,普通视图仅保存查询定义,每次访问都需要重新执行查询,数据字段增多时性能显著下降。而物化视图通过预先复制数据,可实现即时查询响应,代价是需要额外的磁盘空间。

Oracle物化视图的刷新实现方式

物化视图的典型应用场景包括三类:一是缓存本地频繁访问的数据,查询速度远高于直接访问原表或普通视图;二是在本地节点维护远程数据的副本,显著提升跨库读取效率;三是在数据仓库中预先完成表连接或聚合等重型计算,避免每次查询重复计算。数据仓库中还常结合查询重写机制(query rewrite),Oracle自动将原始查询转换为对物化视图的访问,对应用层完全透明。

创建物化视图的语法很简单:

create materialized view mv_name as select * from table_name;

1、预制表

如果已存在一张现成的表,希望将其注册为物化视图,可以使用 ON PREBUILT TABLE。该方式在数据仓库中注册大型物化视图时尤为便捷。需满足两个条件:

  1. 物化视图所在的Schema下必须存在一张同名表,刷新时该表会同步更新。
  2. 该同名表的结构必须与物化视图的SELECT语句返回的字段名完全一致,且一一对应。
# 首先创建一张与物化视图同名的表
CREATE TABLE sales_sum_table(
    month VARCHAR2(8), 
    state VARCHAR2(40), 
    sales NUMBER(10,2)
);
# 创建物化视图,并指定ON PREBUILT TABLE
CREATE MATERIALIZED VIEW sales_sum_table   
   ON PREBUILT TABLE AS 
   SELECT t.calendar_month_desc AS month,
          c.cust_state_province AS state,
          SUM(s.amount_sold) AS sales;

若表或视图列的精度与子查询返回的精度不完全匹配,可通过 WITH REDUCED PRECISION 允许精度损失。

物化视图查询虽快,但基表数据发生变化时,必须同步刷新才能保持数据一致性。

2、物化视图日志

当基表发生DML操作时,Oracle会将变更记录在物化视图日志中,随后利用这些日志执行增量刷新(也称快速刷新)。若缺少日志,则只能将整个查询重新执行一遍(完全刷新)。通常情况下,快速刷新的效率远高于完全刷新。

物化视图日志与主表存储在同一个位置,每张主表对应一个日志。如果物化视图涉及多表JOIN,则参与JOIN的每一张表都需要单独创建日志。

2.1 主键物化视图

主键物化视图记录被更新行的主键值。即使主表发生重组(如分区交换),只要主键不变,快速刷新仍能正常进行。其前提是主表必须启用主键约束,且物化视图的定义查询必须直接引用所有主键列,不能对主键列使用函数(如UPPER)。

对象物化视图不能使用主键,Oracle会隐式地使用对象ID进行刷新。

# 在employees表上创建主键物化视图日志
CREATE MATERIALIZED VIEW LOG ON employees
WITH PRIMARY KEY;

2.2 ROWID物化视图

如果物化视图未包含主表的所有主键列,则需使用ROWID来记录变更。ROWID物化视图只能基于单表,不支持多表JOIN。此外,主表重组后,必须执行一次完全刷新才能恢复快速刷新能力。

使用ROWID时,不能包含以下内容:

  • distinct 或聚集函数
  • GROUP BY或CONNECT BY子句
  • 子查询
  • 联接查询
  • 集合操作

Oracle提供两种日志记录方式:

  1. 默认基于时间戳(timestamp)记录操作提交时间,刷新时需要额外设置,速度稍慢。
  2. 基于SCN(system change number)记录提交顺序,系统通过累加递增数字标记操作先后,通过 COMMIT SCN 指定。

3、刷新方法

物化视图共有四种刷新方式:

3.1 FAST

增量刷新,仅刷新上次刷新之后的修改。常规DML的修改存储在物化视图日志中,direct-path INSERT操作的变化则存储在direct loader日志中(Oracle自动创建)。

使用限制:

  1. 创建物化视图前必须在主表上先创建物化视图日志。
  2. 如果查询包含分析函数或XMLTable函数,则无法使用快速刷新。

3.2 COMPLETE

完全刷新,将物化视图定义的查询重新执行一遍,不论之前是否有增量。即使设置了快速刷新,也可以手动指定执行完全刷新。

3.3 FORCE

刷新时先判断能否执行快速刷新,能则用FAST,不能则降级为COMPLETE。这是一种“保底”模式。

4、刷新时机

物化视图的刷新时机有 ON COMMITON DEMAND 两种,二者互斥,默认采用 ON DEMAND。也可以使用 NEXT 自定义刷新频率。

4.1 ON COMMIT

每当基表上有事务提交时,物化视图会自动刷新。由于刷新动作嵌入在提交事务的流程中,会增加事务的响应时间。

使用限制:

  1. 不能与 ON DEMANDSTART WITHNEXT 一起使用。
  2. 不支持包含对象类型或Oracle内置类型的物化视图。
  3. 不支持涉及远程表的物化视图。
  4. 不能与基表上的分布式事务同时使用。

4.2 ON DEMAND

通过手动调用 DBMS_MVIEW 包中的刷新过程来触发刷新,共有三个刷新过程可供使用。

使用限制:不能与 ON COMMIT 同时使用,若同时指定了 START WITHNEXT 子句,则以它们为准。

4.3 START WITH & NEXT

START WITH 指定第一次自动刷新的时间,NEXT 指定后续自动刷新的间隔。两个表达式都必须返回未来的时间。如果省略 START WITH,Oracle会根据物化视图的创建时间和 NEXT 表达式自动计算第一次刷新时间。如果省略 NEXT,物化视图只会被刷新一次。

create materialized view mv_emp_pk
   build deferred
   refresh fast
   start with sysdate       -- 首次刷新时间:现在
   next sysdate + 7         -- 刷新周期:每7天一次
   with primary key
   as select * from emp;

4.4 NEVER REFRESH

彻底禁止物化视图被任何Oracle刷新机制刷新。如需取消该限制,可使用 ALTER MATERIALIZED VIEW ... REFRESH 进行修改。

5、其他特性

USING CONSTRAINTS

USING ... CONSTRAINTS 子句让Oracle在刷新操作中能够选择更多重写选项,从而提升执行效率。

FOR UPDATE

主键物化视图若指定了 FOR UPDATE,则允许对其进行更新操作。修改完成后,变更数据会以行级单位(通过主键定位)传播回基表。

CREATE MATERIALIZED VIEW foreign_customers FOR UPDATE
AS SELECT * FROM sh.customers@remote cu
WHERE EXISTS (
    SELECT * FROM sh.countries@remote co
    WHERE co.country_id = cu.country_id
);

BUILD

通过 BUILD 子句控制物化视图何时填充数据:

  1. BUILD IMMEDIATE:创建的同时根据主表生成数据(默认)。
  2. BUILD DEFERRED:创建时不生成数据,后续可通过完全刷新来填充。

QUERY REWRITE

查询重写是物化视图的杀手级特性:当用户对基表执行查询时,Oracle自动判断能否利用物化视图来加速,如果可以,就直接从物化视图读取已算好的结果,跳过昂贵的聚合或连接操作。使用 ENABLE QUERY REWRITE 可开启该功能。

总结

物化视图是一个非常实用的数据库对象,合理使用能极大提升查询性能,尤其在数据仓库和报表场景中效果显著。但需注意管理好刷新策略和日志开销,避免物化视图本身成为运维负担。

来源:https://www.jb51.net/database/367229i30.htm
上一篇MySQL 5.7到8迁移:GROUP BY差异与优化建议 下一篇Oracle物化视图如何高效优化多表查询速度详解
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
为什么SQL中 NOT IN 子查询遇到 NULL 会导致 JOIN 逻辑完全崩溃失效
数据库 · 2026-07-21

为什么SQL中 NOT IN 子查询遇到 NULL 会导致 JOIN 逻辑完全崩溃失效

SQL的NOTIN子查询若结果包含NULL,三值逻辑会使整行判断为UNKNOWN,WHERE仅保留TRUE,导致所有行被过滤,返回空集。推荐使用NOTEXISTS替代,它不比较值,只判断子查询是否返回行,天然规避NULL问题。LEFTJOIN+ISNULL易写错,COALESCE或加ISNOTNULL仅权宜之计,可能掩盖数据问题。

完整Redis集群架构图及搭建步骤详解,新手必看
数据库 · 2026-07-21

完整Redis集群架构图及搭建步骤详解,新手必看

一、简介 Redis集群功能从3 0版本开始引入,到5 0 14版本已经相当成熟。本文就来聊聊如何搭建一个最简单的集群,以及常用的集群管理命令。版本锁定在5 0 14,所有操作均基于此版本。 二、架构图 先来看一个最基础的集群架构,一目了然: 三、搭建集群 3 1、下载 这里是在一台Linux服务器

SQL存储过程结合XML数据类型的高性能解析技巧
数据库 · 2026-07-21

SQL存储过程结合XML数据类型的高性能解析技巧

直接用 nodes() + value(),别碰 OPENXML 从 SQL Server 2005 起,OPENXML 就应该被淘汰了。它需要手动调用 sp_xml_preparedocument 和 sp_xml_removedocument,一旦遗漏后者就会引发内存泄漏;而且整个过程基于临

SQL窗口函数生成带层级结构的财务流水号技巧
数据库 · 2026-07-21

SQL窗口函数生成带层级结构的财务流水号技巧

财务流水号按业务类型分组连续编号,需用ROW_NUMBER()OVER(PARTITIONBYbusiness_typeORDERBYcreate_time)生成,避免先GROUPBY致明细丢失。日期前缀和补零拼接需注意数据库差异。多级嵌套结构需在PARTITIONBY中增加额外分类字段,并发环境下窗口函数无法保证唯一性,需结合序列或锁机制。

SQL中COALESCE函数优雅处理NULL值技巧与最佳实践全面指南
数据库 · 2026-07-21

SQL中COALESCE函数优雅处理NULL值技巧与最佳实践全面指南

COALESCE函数从左到右返回首个非NULL值,参数顺序决定兜底是否生效;类型不兼容时PostgreSQL和SQLServer报错,需显式CAST对齐;运算前需对每个可能为NULL的项单独包裹,否则表达式整体为NULL;避免在WHERE或JOIN条件中使用,否则导致语义错乱或索引失效;不处理空字符串,需嵌套NULLIF。