1.1.1.1.1 开启查询重写
从分析结果来看,SALES_MV在TRUESTED模式下已经过时。
最简单的方法是刷新sales_mv物化视图。但这种方式不是我们这章节要讲的内容。
在前面章节已经提到过基表数据和物化视图容器表数据不一致,存在脏数据的情况下,如果还需要使用查询重写。则需修改query_rewrite_integrity为stale_tolerated.
SQL> alter system set query_rewrite_integrity=stale_tolerated;
系统已更改。
1.1.1.1.2 分析语句是否可以查询重写
修改完毕后,再次分析查询重写
10G>truncate table rewrite_table;
表被截断。
10G>execute dbms_mview.Explain_Rewrite(query=>'select upper(p.prod_category) as prod_c
ory,sum(s.amount_sold) as amount_sold from sales s, products p where s.prod_id = p.pro
group by p.prod_category order by p.prod_category',mv=>'sales_mv',statement_id=>'42')
PL/SQL 过程已成功完成。
10G>select message from rewrite_table where statement_id='42';
MESSAGE
--------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------
--------------------------------------------------------------
QSM-01151: 已重写查询
QSM-01033: 已用实体化视图 SALES_MV 进行重写查询
通过分析表明,该SQL语句支持查询重写。我们再通过语句的执行计划看一下。
SQL> l
1 select upper(p.prod_category),
2 sum(s.amount_sold) as amount_sold
3 from sales s,products p
4 where s.prod_id=p.prod_id
5 group by p.prod_category
6* order by p.prod_category
SQL> /
执行计划
----------------------------------------------------------
Plan hash value: 3163011340
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 105 | 4 (25)| 00:00:01 |
| 1 | SORT GROUP BY | | 5 | 105 | 4 (25)| 00:00:01 |
| 2 | MAT_VIEW REWRITE ACCESS FULL| SALES_MV | 81 | 1701 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------------------
很明显,已经访问了物化视图。
1.2 物化视图刷新
1.2.1 手动刷新
1.2.1.1 单线程刷新
1.2.1.1.1 Refresh
SQL> exec dbms_mview.refresh(list=>'SH.SALES_MV');
PL/SQL 过程已成功完成。
1.2.1.1.2 refresh_all_mviews
SQL>set serveroutput on;
SQL> declare
2 i number;
3 begin
4 dbms_mview.refresh_all_mviews(number_of_failures=>i);
5 dbms_output.put_line(‘number_of_failures=>’||i);
6 end;
7 /
number_of_failures=>0
删除当前用户下的所有物化视图,除非对应的物化视图被标记为永不刷新。
Number_of_failures表示刷新物化视图失败个数。因为要刷新数据库中所有的物化视图,所以在生产环境上不建议使用。这将消耗大量的CPU及IO以及影响生产环境的正常使用。
1.2.1.1.3 refresh_dependent
SQL> declare
2 i binary_integer;
3 begin
4 dbms_mview.refresh_dependent(number_of_failures => i,list=>'sh.sales_mv');
5 dbms_output.put_line('number_of_failures=>'||i);
6 end;
7 /
number_of_failures=>0
Number_of_failures表示刷新物化视图失败个数。
1.2.1.2 并行刷新
1.2.1.2.1 Refresh
SQL> exec dbms_mview.refresh(list=>'SH.SALES_MV',parallelism => 2);
PL/SQL 过程已成功完成。
1.2.1.2.2 refresh_all_mviews
SQL>set serveroutput on;
SQL> declare
2 i number;
3 begin
4 dbms_mview.refresh_all_mviews(number_of_failures=>i,parallelism => 2);
5 dbms_output.put_line(‘number_of_failures=>’||i);
6 end;
7 /
number_of_failures=>0
删除当前用户下的所有物化视图,除非对应的物化视图被标记为永不刷新。
Number_of_failures表示刷新物化视图失败个数。在生产环境上不建议使用。这将消耗大量的CPU及IO以及影响生产环境的正常使用。
1.2.1.2.3 refresh_dependent
SQL> declare
2 i binary_integer;
3 begin
4 dbms_mview.refresh_dependent(number_of_failures => i,list=>'sh.sales_mv', ,parallelism => 2);
5 dbms_output.put_line('number_of_failures=>'||i);
6 end;
7 /
number_of_failures=>0
Number_of_failures表示刷新物化视图失败个数。
1.2.2 自动刷新
1.2.2.1 定时刷新
根据业务的需要,物化视图可以提供定时刷新的功能。其原理是Oracle的job任务调用对应的物化视图名称。根据Job触发的时间刷新物化视图。
SQL> alter materialized view sales_mv refresh complete on demand
2 start with sysdate next sysdate+to_dsinterval('0 00:10:00');
实体化视图已更改。
每10分钟刷新sales_mv物化视图。
1.2.2.2 快速刷新
让物化视图支持快速刷新必须在对应的基表上建立物化视图日志。因为快速刷新需要日志来记录数据增量,这里可以设置基于ROWID来将增量同步到容器表。
在三个基表上建立物化视图日志
SQL> create materialized view log on sales with rowid;
实体化视图日志已创建。
SQL> create materialized view log on customers with rowid;
实体化视图日志已创建。
SQL> create materialized view log on products with rowid;
实体化视图日志已创建。
分析是否可以支持快速刷新
在分析前需要导入@?/rdbms/admin/utlxmv.sql.
则会建立
MV_CAPABILITIES_TABLE表。该表用于记录分析日志。
SQL> @?/rdbms/admin/utlxmv.sql
表已创建。
SQL> exec dbms_mview.explain_mview(mv=>'sh.sales_mv',stmt_id=>'42');
PL/SQL 过程已成功完成。
SQL> select capability_name,possible,msgtxt,related_text from mv_capabilities_table
2 where statement_id='42'
3 and capability_name like 'REFRESH_FAST_AFTER%'
4 order by seq;
CAPABILITY_NAME POSSIBLE MSGTXT
RELATED_TEXT
-------------------------------------------------- ---------- ----------------------------
---------------------------------------------------- --------------------
REFRESH_FAST_AFTER_INSERT N 实体化视图日志必须具有新值
SH.PRODUCTS
REFRESH_FAST_AFTER_INSERT N 实体化视图日志不具有某些必需
的列 SH.PRODUCTS
REFRESH_FAST_AFTER_INSERT N 实体化视图日志必须具有新值
SH.CUSTOMERS
REFRESH_FAST_AFTER_INSERT N 实体化视图日志不具有某些必需
的列 SH.CUSTOMERS
REFRESH_FAST_AFTER_INSERT N 实体化视图日志必须具有新值
SH.SALES
REFRESH_FAST_AFTER_INSERT N 实体化视图日志不具有某些必需
的列 SH.SALES
REFRESH_FAST_AFTER_ONETAB_DML N 使用 SUM(expr) 时, 未提供 CO
UNT(expr) AMOUNT_SOLD
REFRESH_FAST_AFTER_ONETAB_DML N 使用 SUM(expr) 时, 未提供 CO
UNT(expr) QUANTITY_SOLD
REFRESH_FAST_AFTER_ONETAB_DML N 查看禁用 REFRESH_FAST_AFTER_
INSERT 的原因
REFRESH_FAST_AFTER_ONETAB_DML N 在选择列表中不存在 COUNT(*)
REFRESH_FAST_AFTER_ONETAB_DML N 使用 SUM(expr) 时, 未提供 CO
UNT(expr)
REFRESH_FAST_AFTER_ANY_DML N mv 日志没有序列号
SH.PRODUCTS
REFRESH_FAST_AFTER_ANY_DML N mv 日志没有序列号
SH.CUSTOMERS
REFRESH_FAST_AFTER_ANY_DML N mv 日志没有序列号
SH.SALES
REFRESH_FAST_AFTER_ANY_DML N 查看禁用 REFRESH_FAST_AFTER_
ONETAB_DML 的原因
已选择15行。
不能快速刷新的原因有很多,我们先看第一个原因。“实体化视图日志必须具有新值”
而目前物化视图日志默认只有老值。所以要设置物化视图日志属性包括新值。
重建物化视图日志之前,先删除它。
SQL> drop materialized view log on sales;
实体化视图日志已删除。
SQL> drop materialized view log on customers;
实体化视图日志已删除。
SQL> drop materialized view log on products;
实体化视图日志已删除。
重建物化视图日志
SQL> create materialized view log on sales with rowid,sequence
2 (cust_id,prod_id,quantity_sold,amount_sold) including new values;
实体化视图日志已创建。
SQL> create materialized view log on customers with rowid,sequence
2 (cust_id,country_id) including new values;
实体化视图日志已创建。
SQL> create materialized view log on products with rowid,sequence
2 (prod_id,prod_category) including new values;
实体化视图日志已创建。
重新分析快速刷新
SQL> exec dbms_mview.refresh(list=>'sh.sales_mv');
PL/SQL 过程已成功完成。
SQL> drop table mv_capabilities_table;
表已删除。
SQL> @?/rdbms/admin/utlxmv.sql
表已创建。
SQL> exec dbms_mview.explain_mview(mv=>'sh.sales_mv',stmt_id=>'42');
PL/SQL 过程已成功完成。
SQL> select capability_name,possible,msgtxt,related_text from mv_capabilities_table
2 where statement_id='42'
3 and capability_name like 'REFRESH_FAST_AFTER%'
4 order by seq;
CAPABILITY_NAME POSSIBLE MSGTXT
RELATED_TEXT
-------------------------------------------------- ---------- ----------------------------
---------------------------------------------------- --------------------
REFRESH_FAST_AFTER_INSERT Y
REFRESH_FAST_AFTER_ONETAB_DML N 使用 SUM(expr) 时, 未提供 CO
UNT(expr) AMOUNT_SOLD
REFRESH_FAST_AFTER_ONETAB_DML N 使用 SUM(expr) 时, 未提供 CO
UNT(expr) QUANTITY_SOLD
REFRESH_FAST_AFTER_ONETAB_DML N 在选择列表中不存在 COUNT(*)
REFRESH_FAST_AFTER_ANY_DML N 查看禁用 REFRESH_FAST_AFTER_
ONETAB_DML 的原因
不能快速刷新的原因少了很多。再看第一个原因。