首页 > 数据库DBA > oracle知识 > oracle_SQL >

物化视图————为提升性能

作者: 初见博客 分类: oracle_SQL 发布时间: 2021-07-09 15:25

Oracle的物化视图提供了强大的功能,可以用于预先计算并保存表连接、聚集等 耗时较多的操作的结果。

这样,在执行查询时,就可以避免进行这些耗时的操作,从而快速地得到结果。

物化视图有很多方面和索引相似

    a、使用物化视图的目的是为了提高查询性能

    b、物化视图对应用透明,增加和删除物化视图不会影响应用程序中SQL语句的正确性和有效性

    c、物化视图需要占用存储空间;

    d、当基表发生变化时,物化视图也应当刷新。

    物化视图可以分为以下三种类型:

     1、包含聚集的物化视图

     2、只包含连接的物化视图

     3、嵌套物化视图。

    三种物化视图的快速刷新的限制条件有很大区别,而对于其他方面则区别不大。

    创建物化视图时可以指定多种选项,下面对几种主要的选择进行简单说明:

  ☞<1>.创建方式(Build Methods):包括 BUILD IMMEDIATE 和 BUILD DEFERRED 两种。BUILD IMMEDIATE [默认方式] 是在创建物化视图的时候就生成数据,而BUILD DEFERRED 则在创建时不生成数据,以后根据需要再生成数据。

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

  ☞<3>.刷新(refresh):指当基表发生了 DML 操作后,物化视图何时采用哪种方式和基表进行同步。刷新的模式有两种:ON DEMAND 和 ON COMMIT。 ON DEMAND 指物化视图在用户需要的时候进行刷新,可以手工通过 DBMS_MVIEW.REFRESH 等方法来进行刷新,也可以通过 JOB 定时进行刷新。 ON COMMIT指出物化视图在对基表的DML操作提交的同时进行刷新。刷新的方法有四种:FAST、COMPLETE、FORCE、NEVER。 FAST刷新采用增量刷新,只刷新自上次刷新以后进行的修改。COMPLETE 刷新对整个物化视图进行完全的刷新。FORCE方式,则Oracle在刷新时会去判断是否可以进行快速刷新,如果可以则采用FAST方式,否则采用complete方式。 NEVER 指物化视图不进行任何刷新。 默认值是 FORCE ON DEMAND。

在建立物化视图的时候可以指定ORDER BY语句,使生成的数据按照一定的顺序进行保存。不过这个语句不会写入物化视图的定义中,而且对以后的刷新也无效。

物化视图日志:如果需要进行快速刷新,则需要建立物化视图日志。物化视图日志根据不同物化视图的快速刷新的需要,可以建立为ROWID或PRIMARY KEY类型的。还可以选择是否包括SEQUENCE、INCLUDING NEW VALUES以及指定列的列表。

可以指明ON PREBUILD TABLE语句将物化视图建立在一个已经存在的表上。这种情况下,物化视图和表必须同名。当删除物化视图时,不会删除同名的表。这种物化视图的查询重写要求参数QUERY_REWRITE_INTEGERITY必须设置为trusted或者stale_tolerated。

物化视图可以进行分区。而且基于分区的物化视图可以支持分区变化跟踪(PCT)。具有这种特性的物化视图,当基表进行了分区维护操作后,仍然可以进行快速刷新操作。 对于聚集物化视图,可以在GROUP BY列表中使用CUBE或ROLLUP,来建立不同等级的聚集物化视图。

物化视图的基本操作和使用可以查看网址:http://blog.itpub.net/post/468/13318 相关的东东。我主要说明一下使用物化视图的基本东东。如如何建立在特定的表空间上,这些在其他的物化视图上面几乎都没有任何介绍的。主要以我做的一个例子来操作,如果对物化视图的基本概念清楚了就比较明白在那里写特定的表空间存储了。

创建物化视图时应先创建存储的日志空间
CREATE MATERIALIZED VIEW LOG ON mv_lvy_levytaxbgtdiv
tablespace ZGMV_DATA –日志保存在特定的表空间
WITH ROWID ;
CREATE MATERIALIZED VIEW LOG ON tb_lvy_levydetaildata
tablespace ZGMV_DATA –日志保存在特定的表空间
WITH ROWID,sequence(LEVYDETAILDATAID);
CREATE MATERIALIZED VIEW LOG ON tb_lvy_levydata
tablespace ZGMV_DATA –日志保存在特定的表空间
WITH rowid,sequence(LEVYDATAID);
然后创建物化视图
–创建物化视图
create materialized view MV_LVY_LEVYDETAILDATA
TABLESPACE ZGMV_DATA –保存表空间
BUILD DEFERRED –延迟刷新不立即刷新
refresh force –如果可以快速刷新则进行快速刷新,否则完全刷新
on demand –按照指定方式刷新
start with to_date(’24-11-2005 18:00:10′, ‘dd-mm-yyyy hh24:mi:ss’) –第一次刷新时间
next TRUNC(SYSDATE+1)+18/24 –刷新时间间隔
as
SELECT levydetaildataid, detaildatano, taxtermbegin, taxtermend,
……
ROUND(taxdeduct * taxpercent1, 2) – ROUND(taxdeduct * taxpercent2, 2) –
ROUND(taxdeduct * taxpercent3, 2) – ROUND(taxdeduct * taxpercent4, 2) –
ROUND(taxdeduct * taxpercent5, 2) taxdeduct, ROUND(taxfinal * taxpercent1, 2) –
ROUND(taxfinal * taxpercent2, 2) – ROUND(taxfinal * taxpercent3, 2) –
ROUND(taxfinal * taxpercent4, 2) – ROUND(taxfinal * taxpercent5, 2) taxfinal,
a.levydataid, a.budgetitemcode, taxtypecode,
……
FROM tb_lvy_levydetaildata a, tb_lvy_levydata c, MV_LVY_LEVYTAXBGTDIV b
WHERE a.levydataid = c.levydataid
AND a.budgetdistrscalecode = b.budgetdistrscalecode
AND a.budgetitemcode = b.budgetitemcode
AND c.incomeresidecode = b.rcvfisccode
AND C.TAXSTATUSCODE=’08’
AND C.NEGATIVEFLAG!=’9′
删除物化视图日志
–删除物化视图:
–删除日志: DROP materialized view log on mv_lvy_levytaxbgtdiv;
DROP materialized view log on tb_lvy_levydetaildata;
DROP materialized view log on tb_lvy_levydata;
–删除物化视图 drop materialized view MV_LVY_LEVYDETAILDATA;
–基本和对表的操作一致 –物化视图由于是物理真实存在的,故可以创建索引。
创建方式和对普通表创建方式相同,就不在重复写了。

==========================================================================================

定位导致物化视图无法快速刷新的原因

物化视图的快速刷新采用了增量的机制,在刷新时,只针对基表上发生变化的数据进行刷新。因此快速刷新是物化视图刷新方式的首选。

但是快速刷新具有较多的约束,而且对于采用ON COMMIT模式进行快速刷新的物化视图更是如此。对于包含聚集和包含连接的物化视图的快速刷新机制并不相同,而且对于多层嵌套的物化视图的快速刷新更是有额外的要求。

如此多的限制一般很难记全,当建立物化视图失败时,Oracle给出的错误信息又过于简单,有时无法使你准确定位到问题的原因。

Oracle提供的DBMS_MVIEW.EXPLAIN_MVIEW过程可以帮助你快速定位问题的原因。下面通过一个例子来说明,如果通过这个过程来解决问题。

建立一个快速刷新的嵌套物化视图:

SQL> CREATE TABLE B (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30));

表已创建。

SQL> CREATE TABLE C (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30));

表已创建。

SQL> CREATE TABLE A (ID NUMBER, BID NUMBER, CID NUMBER, NUM NUMBER,
2  CONSTRAINT FK_A_B_BID FOREIGN KEY (BID) REFERENCES B(ID),
3  CONSTRAINT FK_A_C_BID FOREIGN KEY (CID) REFERENCES C(ID));

表已创建。

SQL> INSERT INTO B SELECT ROWNUM, ‘B’||ROWNUM FROM USER_TABLES WHERE ROWNUM <= 6;

已创建6行。

SQL> INSERT INTO C SELECT ROWNUM, ‘C’||ROWNUM FROM USER_TABLES WHERE ROWNUM <= 4;

已创建4行。

SQL> INSERT INTO A SELECT ROWNUM, TRUNC((ROWNUM – 1)/2) + 1, TRUNC((ROWNUM – 1)/3) + 1, ROWNUM
2  FROM USER_TABLES
3  WHERE ROWNUM <= 12;

已创建12行。

SQL> COMMIT;

提交完成。

上面建立好基表,下面建立第一层物化视图。

SQL> CREATE MATERIALIZED VIEW LOG ON A WITH ROWID;

实体化视图日志已创建。

SQL> CREATE MATERIALIZED VIEW LOG ON B WITH ROWID;

实体化视图日志已创建。

SQL> CREATE MATERIALIZED VIEW LOG ON C WITH ROWID;

实体化视图日志已创建。

SQL> CREATE MATERIALIZED VIEW MV_ABC REFRESH FAST ON COMMIT ENABLE QUERY REWRITE AS
2  SELECT C.ID CID, C.NAME CNAME, B.ID BID, B.NAME BNAME, A.NUM,
3  A.ROWID AROWID, B.ROWID BROWID, C.ROWID CROWID
4  FROM A, B, C WHERE A.BID = B.ID AND A.CID = C.ID;

实体化视图已创建。

第一次物化视图已经建立成功,下面建立嵌套物化视图:

SQL> CREATE MATERIALIZED VIEW LOG ON MV_ABC WITH ROWID (BNAME, CNAME, NUM) INCLUDING NEW VALUES;

实体化视图日志已创建。

SQL> CREATE MATERIALIZED VIEW MV_MV_ABC REFRESH FAST ON COMMIT ENABLE QUERY REWRITE AS
2  SELECT CNAME, BNAME, COUNT(*) COUNT, SUM(NUM) SUM_NUM FROM MV_ABC
3  GROUP BY CNAME, BNAME;
SELECT CNAME, BNAME, COUNT(*) COUNT, SUM(NUM) SUM_NUM FROM MV_ABC
*
ERROR 位于第 2 行:
ORA-12053: 这不是一个有效的嵌套实体化视图

错误出现了,不过错误的描述包含的信息量并不大。我们看看Oracle的文档上是如何描述这个错误的。

ORA-12053 this is not a valid nested materialized view

Cause: The list of objects in the FROM clause of the definition of this materialized view had some dependencies upon each other.

Action: Refer to the documentation to see which types of nesting are valid.

文档上的描述也是十分笼统的,并没有指出具体问题所在。

接下来,我们通过使用DBMS_MVIEW.EXPLAIN_MVIEW过程来定位错误。

使用EXPLAIN_MVIEW 过程首先要建立MV_CAPABILITIES_TABLE表,建表的脚步是$ORACLE_HOME/rdbms/admin/utlxmv.sql。(EXPLAIN_MVIEW过程是两个过程的重载,一个输出到MV_CAPABILITIES_TABLE表,另一个以PL/SQL的VARRAY格式输出,为了简单起见,我们建立MV_CAPABILITIES_TABLE表)。

SQL> @?rdbmsadminutlxmv.sql

表已创建。

下面简单研究一下EXPLAIN_MVIEW过程。

DBMS_MVIEW.EXPLAIN_MVIEW(mv IN VARCHAR2, Statement_id IN VARCHAR2:= NULL);

该过程可以输入已经存在的物化视图名称(或USER_NAME.MV_NAME),也可输入建立物化视图的查询语句。另外一个参数STATEMENT_ID输入一个语句ID,为了标识出表中对应的记录。

SQL> BEGIN
2  DBMS_MVIEW.EXPLAIN_MVIEW(‘SELECT CNAME, BNAME, COUNT(*) COUNT, SUM(NUM) SUM_NUM FROM MV_ABC
3  GROUP BY CNAME, BNAME’, ‘MV_MV_ABC’);
4  END;
5  /

PL/SQL 过程已成功完成。

SQL> SELECT CAPABILITY_NAME, RELATED_TEXT, MSGTXT FROM MV_CAPABILITIES_TABLE
2  WHERE STATEMENT_ID = ‘MV_MV_ABC’ AND POSSIBLE = ‘N’ AND CAPABILITY_NAME NOT LIKE ‘%PCT%’;

CAPABILITY_NAME                RELATED_TEXT    MSGTXT
—————————— ————— ————————————————–
REFRESH_FAST_AFTER_ONETAB_DML  SUM_NUM         使用 SUM(expr) 时, 未提供 COUNT(expr)
REFRESH_FAST_AFTER_ANY_DML     YANGTK.MV_ABC   mv 日志没有序列号
REFRESH_FAST_AFTER_ANY_DML                     查看禁用 REFRESH_FAST_AFTER_ONETAB_DML 的原因

根据上面的信息,已经可以确定问题的原因了,对于聚集物化视图,使用了SUM(COLUMN),但是没有包括COUNT(COLUMN)。

修改物化视图,重新建立:

SQL> CREATE MATERIALIZED VIEW MV_MV_ABC REFRESH FAST ON COMMIT ENABLE QUERY REWRITE AS
2  SELECT CNAME, BNAME, COUNT(*) COUNT, COUNT(NUM) NUM_COUNT, SUM(NUM) SUM_NUM FROM MV_ABC
3  GROUP BY CNAME, BNAME;

实体化视图已创建。

补:deferred:延迟的

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注