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 的原因

不能快速刷新的原因少了很多。再看第一个原因。