暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle物化视图的用法

原创 逆风飞翔 2022-11-28
1398

物化视图,说白了,就是物理表,只不过这张表通过oracle的内部机制可以定期更新,将一些大的耗时的表连接用物化视图实现,会提高查询的效率。当然要打开查询重写选项;
简而言之,就是具有实体表的视图,而且这个视图还可以根据多种需求和策略进行刷新。此外还有一个非常重要的功能
查询重写(query rewrite) .查询重写能够在某些时候提高你的查询速度。
所谓查询重写,简而言之,就是oracle 的查询优化器发现有个物化视图的语法和你的SQL差不多,那么就会直接访问物化视图,而不是你原来查询中有关的源表。
物化视图能干什么?
或者说,你能拿物化视图做什么用。
前文简单说了下,此处列出一些重要而想详细的功能:
能够提高查询速度,这主要是因为物化视图存储了实际的数据,其次具有查询重写功能。最后,物化视图具有实体表,你也可以在上面建立索引,总之大体上当作一个表用就可以了。
简化了开发任务,意思是开发的人员有的时候,无需直接关注部分sql的性能,而通过dba的努力,使用查询重写来完成性能的提升。
减少了工作量,因为物化视图可以定义两种刷新方式:立即刷新,按需刷新。所谓按需刷新就是你自己手动刷新,或者是定时刷新;所谓立即刷新,即视图主表发生变化的时候,视图立即刷新内容。 你可以根据自己的设备情况,应用情况和需求来控制刷新的方式。
刷新量的灵活限制,你可以快速是刷新(只刷新变化的),也可以全刷新。看你的需要。
物化视图可以分为以下三种类型
包含聚集的物化视图;
只包含连接的物化视图;
嵌套物化视图。
三种物化视图的快速刷新的限制条件有很大区别,而对于其他方面则区别不大。创建物化视图时可以指定多种选项,下面对几种主要的选择进行简单说明:
创建方式(BuildMethods):包括BUILD IMMEDIATE和BUILD DEFERRED两种。
BUILD IMMEDIATE是在创建物化视图的时候就生成数据。
BUILD DEFERRED则在创建时不生成数据,以后根据需要在生成数据。默认为BUILD IMMEDIATE。

查询重写(QueryRewrite):包括ENABLE QUERY REWRITE和DISABLE QUERY REWRITE两种。
分别指出创建的物化视图是否支持查询重写。查询重写是指当对物化视图的基表进行查询时,Oracle会自动判断能否通过查询物化视图来得到结果,如果可以,则避免了聚集或连接操作,而直接从已经计算好的物化视图中读取数据。默认为DISABLE QUERY REWRITE。

刷新(Refresh):指当基表发生了DML操作后,物化视图何时采用哪种方式和基表进行同步。刷新的模式有两种:ON DEMAND和ON COMMIT。ON DEMAND和ON COMMIT物化视图的区别在于其刷新方法的不同,
ON DEMAND指物化视图在用户需要的时候进行刷新,可以手工通过DBMS_MVIEW.REFRESH等方法来进行刷新,也可以通过JOB定时进行刷新,即更新物化视图,以保证和基表数据的一致性;
而ON COMMIT是说,一旦基表有了COMMIT,即事务提交,则立刻刷新,立刻更新物化视图,使得数据和基表一致。对基表,平常的COMMIT在0.01秒内可以完成,但在有了ON COMMIT视图后,居然要6秒。速度减低了很多倍。ON COMMIT视图对基表的影响可见一斑。
物化视图,根据不同的着重点可以有不同的分类:
按刷新方式分:FAST/COMPLETE/FORCE
按刷新时间的不同:ON DEMAND/ON COMMIT
按是否可更新:UPDATABLE/READ ONLY
按是否支持查询重写:ENABLE QUERY REWRITE/DISABLEQUERY REWRITE
默认情况下,如果没指定刷新方法和刷新模式,则Oracle默认为FORCE和DEMAND。
注意:设置REFRESH ON COMMIT的物化视图不能访问远端对象。
在建立物化视图的时候可以指定ORDER BY语句,使生成的数据按照一定的顺序进行保存。不过这个语句不会写入物化视图的定义中,而且对以后的刷新也无效。
物化视图有三种刷新方式:COMPLETE、FAST和 FORCE。
完全刷新(COMPLETE)会删除表中所有的记录(如果是单表刷新,可能会采用TRUNCATE的方式),然后根据物化视图中查询语句的定义重新生成物化视图。
快速刷新(FAST)采用增量刷新的机制,只将自上次刷新以后对基表进行的所有操作刷新到物化视图中去。FAST必须创建基于主表的视图日志。对于增量刷新选项,如果在子查询中存在分析函数,则物化视图不起作用。

采用FORCE方式,Oracle会自动判断是否满足快速刷新的条件,如果满足则进行快速刷新,否则进行完全刷新。

Oracle物化视图的快速刷新机制是通过物化视图日志完成的。Oracle通过一个物化视图日志还可以支持多个物化视图的快速刷新。物化视图日志根据不同物化视图的快速刷新的需要,可以建立为ROWID或PRIMARY KEY类型的。还可以选择是否包括SEQUENCE、INCLUDING NEW VALUES以及指定列的列表。
物化视图操作示例



-- 物化视图操作示例

-- 删除物化视图

DROP MATERIALIZED VIEW V_RPT_ACT_ACTION;


-- 创建物化视图

/**

1.创建方式(BuildMethods):包括BUILD IMMEDIATE和BUILD DEFERRED两种。

BUILD IMMEDIATE是在创建物化视图的时候就生成数据。

BUILD DEFERRED则在创建时不生成数据,以后根据需要在生成数据。默认为BUILD IMMEDIATE。


2. 查询重写(QueryRewrite):包括ENABLE QUERY REWRITE和DISABLE QUERY REWRITE两种。

分别指出创建的物化视图是否支持查询重写。

查询重写是指当对物化视图的基表进行查询时,

Oracle会自动判断能否通过查询物化视图来得到结果,如果可以,则避免了聚集或连接操作,

而直接从已经计算好的物化视图中读取数据。默认为DISABLE QUERY REWRITE。



*/
CREATE MATERIALIZED VIEW V_RPT_ACT_ACTION
BUILD IMMEDIATE
DISABLE QUERY REWRITE
AS
SELECT * FROM T_ACT_ACTION;

-- 查询物化视图

SELECT * FROM V_RPT_ACT_ACTION ORDER BY V_RPT_ACT_ACTION.ACTION_VALUE;

-- 刷新物化视图 刷新时间间隔。每1天刷新一次,时间为凌晨10点

ALTER MATERIALIZED VIEW V_RPT_ACT_ACTION
REFRESH FORCE ON DEMAND
START WITH SYSDATE NEXT TO_DATE(CONCAT(TO_CHAR(SYSDATE+1,'DD-MM-YYYY'),' 22:00:00'),'DD-MM-YYYY HH24:MI:SS');

-- 使用DBMS_MVIEW.REFRESH 手工刷新,刷新物化视图,可以放在存储过程中刷新,存储过程不用写EXEC
-- DBMS_MVIEW.REFRESH('V_RPT_ACT_ACTION');


-- EXEC DBMS_MVIEW.REFRESH('V_RPT_ACT_ACTION');
-- EXEC DBMS_REFRESH.REFRESH('V_RPT_ACT_ACTION');

-- 完全刷新

-- EXEC DBMS_MVIEW.REFRESH(LIST => 'V_RPT_ACT_ACTION',METHOD => 'c');
-- EXEC DBMS_MVIEW.REFRESH('V_RPT_ACT_ACTION','C');

--快速刷新

-- 表 "BOEREMS"."T_ACT_ACTION" 不带实体化视图日志



-- EXEC DBMS_MVIEW.REFRESH(LIST => 'V_RPT_ACT_ACTION',METHOD => 'f');
-- EXEC DBMS_MVIEW.REFRESH('V_RPT_ACT_ACTION','F');

SELECT SYS_GUID() FROM DUAL;

-- 查询物化视图上次刷新时间

-- LAST_REFRESH_DATE 上次刷新时间


SELECT * FROM USER_MVIEWS
WHERE MVIEW_NAME = 'V_RPT_ACT_ACTION';

-- 手动刷新物化视图

BEGIN
DBMS_MVIEW.REFRESH('V_RPT_ACT_ACTION');
END;



CREATE OR REPLACE PROCEDURE USP_RVW_REFRESH_VIEW

AS

BEGIN

-- 刷新物化视图

DBMS_OUTPUT.PUT_LINE('######');

-- DBMS_MVIEW.REFRESH('V_RPT_ACT_ACTION');

DBMS_MVIEW.REFRESH('V_RPT_OBJECTIVE_QUESTIONS','C');

-- EXECUTE IMMEDIATE 'DROP MATERIALIZED VIEW V_RPT_OBJECTIVE_QUESTIONS';

DBMS_MVIEW.REFRESH('V_RPT_COURSE_STUDENT','C');
DBMS_MVIEW.REFRESH('V_RPT_EXAM_STUDENT','C');

-- CALL DBMS_MVIEW.REFRESH('V_RPT_COURSE_STUDENT ','C');
-- CALL DBMS_MVIEW.REFRESH('V_RPT_EXAM_STUDENT ','C');

DBMS_OUTPUT.PUT_LINE('###### FINISH');

END USP_RVW_REFRESH_VIEW;


要想创建 "物化视图,至少具有 ‘CREATE MATERIALIZED VIEW’ 权限"

-- 权限查询,非 DBA 用户,则使用 user_sys_privs 即可
SELECT * FROM dba_sys_privs t WHERE t.privilege LIKE '%MATERIALIZED%';
grant create materialized view to scott; -- 授权
revoke create materialized view from scott; -- 回收


创建物化视图时的选项有很多,知晓常用的即可:

create materialized view 物化视图名 -- 1. 创建物化视图
build [immediate | deferred] -- 2. 创建方式,默认 immediate
refresh [force | fast | complete | never] -- 3. 物化视图刷新方式,默认 force
on [commit | demand] -- 4. 刷新触发方式
start with 开始时间 -- 5. 设置开始时间
next 间隔时间 -- 6. 设置间隔时间
with [primary key | rowid] -- 7. 类型,默认 primary key
[enable | disable] query rewrite -- 8. 是否启用查询重写
as -- 9. 关键字
查询语句; -- 10. select 语句


语法解释:

1. "创建 build" 的方式
(1) 'immediate':立即生效,默认。
(2) 'deferred' : 延迟至第一次 refresh 时才生效
2. "刷新 refresh" 的方式
(1) force :默认。如果可以 '快速刷新' 就 '快速刷新',否则执行 '完全刷新'
(2) fast :'快速刷新'。只刷新 '增量' 部分(前提:创建 '物化日志')
(3) complete: '完全刷新'。刷新时更新全部数据,包括视图中已经生成的原有数据
(4) never : 从不刷新
3. "触发" (请注意,on demand 中,才需要设置 '开始时间' 和 '间隔时间') -- 冲突
(1) on commit:基表有 commit 动作时,刷新刷图("不能跨库执行")
(2) on demand:在需要时刷新
[1] 根据后面设定的 '开始时间' 和 '结束时间' 进行刷新
[2] 手动调用 dbms_mview 包中的过程进行刷新
4. 基于基表的 primary key 或 rowid 创建
(1) 如果是基于 rowid,则不能对基表执行 '分组函数'、'多表连接' 等需要把
多个 rowid 合成一行的操作(理由很简单:到底以哪个 rowid 为准呢?)
5. enable query rewrite 启用查询重写(请注意, '开始时间' 和 '间隔时间' 不支持)-- 冲突
(1) 不支持的理由也很简单。
所谓的 '重写',就是讲对基表的查询定位到物化视图上,
而 '开始时间' 和 '间隔时间' 会造成物化视图上部分数据延迟,所以,不能重写
(2) 参数: query_rewrite_enabled (可通过 v$parameter 视图查询)


示例:每 3 分钟,同步一次基表数据(用户 scott)
1. 先创建基表 person_info,并插入几条数据

CREATE TABLE person_info (
person_no VARCHAR2(10),
NAME VARCHAR2(30),
create_date DATE
);
INSERT INTO person_info(person_no, NAME, create_date) VALUES('001', '瑶瑶', SYSDATE);
INSERT INTO person_info(person_no, NAME, create_date) VALUES('002', '倩倩', SYSDATE);
COMMIT;


2. 创建物化视图:每 3 分钟刷新一次

CREATE MATERIALIZED VIEW mvw_person_info
BUILD IMMEDIATE
REFRESH FORCE
ON DEMAND
START WITH SYSDATE
NEXT SYSDATE + 3/1440
AS
SELECT pi.person_no,
pi.name,
pi.create_date
FROM person_info pi;

测试语句:先查询,等个十几秒在执行 insert,再等 3 分钟左右,观察前后数据

SELECT t.* FROM mvw_person_info t;
INSERT INTO person_info(person_no, NAME, create_date) VALUES('003', '优优', SYSDATE);
COMMIT;

2.2 查询
1. 查询物化视图,非 DBA 用户,请查询 all_mviews 或 user_mviews
SELECT *
FROM dba_mviews t
WHERE t.owner = 'SCOTT'
AND t.mview_name = 'MVW_PERSON_INFO';
2. 查询一般视图
SELECT * FROM dba_views;

2.3 修改
alter materialized view 物化视图名
refresh [force | fast | complete | never]
on [commit | demand]
start with 开始时间
next 间隔时间

2.4 删除
drop materialized view 物化视图名;

3 扩展
3.1 手动刷新
BEGIN
dbms_mview.refresh(list => '视图名',
method => 'fast', -- 增量刷新
refresh_after_errors => TRUE);
END;


3.2 创建物化视图日志
1. 适用于 'fast' 增量刷新
2. with primary key
3. with rowid

3.2.1 with primary key
(1) 首先创建一张表 student_info :

CREATE TABLE student_info (
student_no VARCHAR2(10),
NAME VARCHAR2(30)
);
ALTER TABLE student_info ADD CONSTRAINT pk_student_info_student_no
PRIMARY KEY(student_no);


(2) 然后创建物化视图日志,指定 primary key:

create materialized view log on student_info with primary key
[including new values];
-- including new values 允许 Oracle 将数据库 新、旧值都保存在物化视图日志中
-- 即 update 前 和 update 后都保存,按需设置即可

(3) 然后在基表 student_info 中插入并更新一条记录:

INSERT INTO student_info(student_no, NAME) VALUES('001', '小优子');
UPDATE student_info t SET t.name = '小游子' WHERE t.student_no = '001';
COMMIT;


(4) 最后查询物化视图日志信息:

SELECT * FROM all_mview_logs;
SELECT * FROM mlog$_student_info;


3.2.2 with rowid
创建 'fast' 增量模式的物化视图条件:
(1) select 语句中包含到的每一个表都需要创建 '物化日志'
(2) select 中必须包含涉及到所有表的 'rowid'
(3) select 中必须明确具体的列,不允许使用 '*'


(1) 首先创建两张表:

CREATE TABLE test_a (
a_id VARCHAR(10),
NAME VARCHAR2(30)
);
ALTER TABLE test_a ADD CONSTRAINT pk_test_a_a_id PRIMARY KEY(a_id);
CREATE TABLE test_b (
b_id VARCHAR(10),
NAME VARCHAR2(30)
);
ALTER TABLE test_b ADD CONSTRAINT pk_test_b_b_id PRIMARY KEY(b_id);

(2) 对所有基表创建物化视图日志:

create materialized view log on test_a with rowid including new values;
create materialized view log on test_b with rowid including new values;

(3) 创建 fast 增量模式的物化视图:

CREATE MATERIALIZED VIEW mvw_test_ab
REFRESH FAST WITH ROWID
ON DEMAND
START WITH SYSDATE
NEXT SYSDATE + 3/1440
AS
SELECT t1.a_id,
t1.name a_name,
t1.rowid a_rowid,
t2.b_id,
t2.name b_name,
t2.rowid b_rowid
FROM test_a t1, test_b t2
WHERE t1.a_id = t2.b_id;

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论