materialized views.docx

73
Materialized Views REFRESH FAST Now that we know how materialized view logs track changes to base tables we can use them to perform fast materialized view refreshes, i.e. refreshes where only the individual materialized view rows affected by base table changes are updated. This is also called "incremental" refreshing. Earlier in this tutorial we saw how the rowids for each row in a materialized view changed after a complete refresh. Now let's see what happens to a materialized view's rowids after a fast refresh. First we use the REFRESH FAST clause to specify that the default refresh method should be fast. create materialized view log on t with sequence ; create materialized view mv REFRESH FAST as select * from t ; select key, val, rowid from mv ; KEY VAL ROWID

Upload: mcajava

Post on 01-Nov-2014

166 views

Category:

Documents


0 download

DESCRIPTION

Materialize Views

TRANSCRIPT

Page 1: Materialized Views.docx

Materialized Views

REFRESH FAST

Now that we know how materialized view logs track changes to base tables we can use them to perform fast materialized view refreshes, i.e. refreshes where only the individual materialized view rows affected by base table changes are updated. This is also called "incremental" refreshing.

Earlier in this tutorial we saw how the rowids for each row in a materialized view changed after a complete refresh. Now let's see what happens to a materialized view's rowids after a fast refresh. First we use the REFRESH FAST clause to specify that the default refresh method should be fast.

create materialized view log on t with sequence ;

create materialized view mv

REFRESH FAST

as select * from t

;

select key, val, rowid

from mv ;

 

KEY VAL ROWID

---------- ----- ------------------

1 a AAAWm+AAEAAAAaMAAA

2 b AAAWm+AAEAAAAaMAAB

3 c AAAWm+AAEAAAAaMAAC

4 AAAWm+AAEAAAAaMAAD

Page 2: Materialized Views.docx

 

Now we refresh the materialized view. The "F" value for the "method" parameter ensures the refresh will be a Fast one.

execute dbms_mview.refresh( list => 'MV', method => 'F' );

select key, val, rowid

from mv ;

 

KEY VAL ROWID

---------- ----- ------------------

1 a AAAWm+AAEAAAAaMAAA

2 b AAAWm+AAEAAAAaMAAB

3 c AAAWm+AAEAAAAaMAAC

4 AAAWm+AAEAAAAaMAAD

 

The rowids did not change. Thus, with a fast refresh the materialized view data is not touched when no changes have been made to the base table, unlike a complete refresh where each row would have been created anew.

Now let's update a row in the base table.

update t set val = 'XX'

where key = 3 ;

commit;

Page 3: Materialized Views.docx

execute dbms_mview.refresh( list => 'MV', method => 'F' );

select key, val, rowid

from mv ;

 

KEY VAL ROWID

---------- ----- ------------------

1 a AAAWm+AAEAAAAaMAAA

2 b AAAWm+AAEAAAAaMAAB

3 XX AAAWm+AAEAAAAaMAAC

4 AAAWm+AAEAAAAaMAAD

 

Still no change in the rowids. In row 3 we can see that VAL changed from "c" to "XX" though, telling us that row 3 was updated during the refresh.

Defaults

The REFRESH FAST clause of the CREATE MATERIALIZED VIEW command tells Oracle what type of refresh to perform when no refresh option is specified. A materialized view created with REFRESH FAST can still be refreshed completely if required though. In the following example note how, even though MV was created above with the REFRESH FAST clause, all its rowids change after the refresh. This indicates that a complete refresh was performed.

execute dbms_mview.refresh( list => 'MV', method => 'C' );

select key, val, rowid

from mv ;

Page 4: Materialized Views.docx

 

KEY VAL ROWID

---------- ----- ------------------

1 a AAAWm+AAEAAAAaMAAE

2 b AAAWm+AAEAAAAaMAAF

3 XX AAAWm+AAEAAAAaMAAG

4 AAAWm+AAEAAAAaMAAH

 

Similarly a materialized view created with REFRESH COMPLETE can be fast refreshed (assuming the materialized view is capable of being fast refreshed, we'll learn more about this later).

drop materialized view mv ;

create materialized view mv

REFRESH COMPLETE

as select * from t

;

 

select key, val, rowid

from mv ;

KEY VAL ROWID

---------- ----- ------------------

1 a AAAWnBAAEAAAAaMAAA

Page 5: Materialized Views.docx

2 b AAAWnBAAEAAAAaMAAB

3 XX AAAWnBAAEAAAAaMAAC

4 AAAWnBAAEAAAAaMAAD

execute dbms_mview.refresh( list => 'MV', method => 'F' );

select key, val, rowid

from mv ;

KEY VAL ROWID

---------- ----- ------------------

1 a AAAWnBAAEAAAAaMAAA

2 b AAAWnBAAEAAAAaMAAB

3 XX AAAWnBAAEAAAAaMAAC

4 AAAWnBAAEAAAAaMAAD

 

Note how none of the rowids in MV changed, indicating a fast refresh.

Cleanup

drop materialized view mv ;

drop materialized view log on t ;

update t set val = 'c' where key = 3 ;

commit ;

Page 6: Materialized Views.docx

 

Materialized Views

Purging Materialized View Logs

Oracle automatically purges rows in the materialized view log when they are no longer needed. In the example below note how the log table is empty after the refresh.

create materialized view log on t ;

create materialized view mv

refresh fast

as select * from t

;

select count(*) from mlog$_t ;

COUNT(*)

----------

0

insert into t values ( 5, 'e' ) ;

commit;

select count(*) from mlog$_t ;

Page 7: Materialized Views.docx

COUNT(*)

----------

1

execute dbms_mview.refresh( list => 'MV', method => 'F' );

select count(*) from mlog$_t ;

COUNT(*)

----------

0

 

DBMS_MVEW.PURGE_LOG

If a materialized view log needs to be purged manually for some reason a procedure called DBMS_MVEW.PURGE_LOG can be used.

select count(*) from mlog$_t ;

COUNT(*)

----------

0

update t set val = 'X' where key = 5 ;

commit;

select count(*) from mlog$_t ;

Page 8: Materialized Views.docx

COUNT(*)

----------

1

execute DBMS_MVIEW.PURGE_LOG( master => 'T', num => 9999, flag => 'delete' ) ;

select count(*) from mlog$_t ;

COUNT(*)

----------

0

 

The "num" and "flag" parameters can be used to partially purge the log. See the PURGE_LOG manual page for further details.

Once a materialized view log has been purged any materialized views dependent on the deleted rows cannot be fast refreshed. Attempting a fast refresh will raise an error.

execute dbms_mview.refresh( list => 'MV', method => 'F' );

BEGIN dbms_mview.refresh( list => 'MV', method => 'F' ); END;

*

ERROR at line 1:

ORA-12034: materialized view log on "SCOTT"."T" younger than last refresh

ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2537

ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2743

ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2712

Page 9: Materialized Views.docx

ORA-06512: at line 1

 

Such materialized views will need to be refreshed completely.

select * from mv ;

 

KEY VAL

---------- -----

1 a

2 b

3 c

4

5 e

 

execute dbms_mview.refresh( list => 'MV', method => 'C' );

select * from mv ;

 

KEY VAL

---------- -----

1 a

2 b

Page 10: Materialized Views.docx

3 c

4

5 X

 

Cleanup

delete from t where key = 5 ;

commit;

drop materialized view mv ;

drop materialized view log on t ;

 

Materialized Views

REFRESH FAST Categories

There are three ways to categorize a materialized view's ability to be fast refreshed.

1.It can never be fast refreshed.2.It can always be fast refreshed.3.It can be fast refreshed after certain kinds of changes to the base table

but not others.For the first case Oracle will raise an error if you try to create such a materialized view with its refresh method defaulted to REFRESH FAST. In the example below table T does not have a materialized view log on it. Materialized views based on T cannot therefore be fast refreshed. If we attempt to create such a materialized view we get an error.

Page 11: Materialized Views.docx

create materialized view MV

REFRESH FAST

as select * from t2

;

as select * from t2

*

ERROR at line 3:

ORA-23413: table "SCOTT"."T2" does not have a materialized view log

 

For the second case materialized views are created without error, obviously, and will always be fast refreshed unless a complete refresh is explicitly requested. The third case is a little trickier. The next example demonstrates why.

select * from t2 ;

 

KEY T_KEY AMT

---------- ---------- ----------

10 1 100

20 1 300

30 1 200

40 2 250

50 2 150

 

Page 12: Materialized Views.docx

create materialized view log on t2

with primary key, rowid, sequence ( t_key, amt )

including new values

;

create materialized view mv

REFRESH FAST

as

select t_key, max( amt ) amt_max

from t2

group by t_key

;

select rowid, t_key, amt_max from mv ;

 

ROWID T_KEY AMT_MAX

------------------ ---------- ----------

AAAhMzAAEAAAEG8AAA 1 300

AAAhMzAAEAAAEG8AAB 2 250

 

So far everything works as expected. We created a materialized view log and created a materialized view with fast refresh as its default refresh method. Let's try inserting a row into the base table.

insert into t2 values ( 5, 2, 500 );

Page 13: Materialized Views.docx

commit;

execute dbms_mview.refresh( list => 'MV', method => 'F' );

select rowid, t_key, amt_max from mv ;

 

ROWID T_KEY AMT_MAX

------------------ ---------- ----------

AAAhMzAAEAAAEG8AAA 1 300

AAAhMzAAEAAAEG8AAB 2 500

 

Again, it worked as expected. The view was fast refreshed (the rowid's did not change after the DBMS_MVIEW.REFRESH command) and the materialized view correctly shows 500 as the maximum value for rows with T_KEY = 2. Now let's try deleting a row from the base table.

delete from t2 where key = 5 ;

commit;

execute dbms_mview.refresh( list => 'MV', method => 'F' );

BEGIN dbms_mview.refresh( list => 'MV', method => 'F' ); END;

*

ERROR at line 1:

ORA-32314: REFRESH FAST of "SCOTT"."MV" unsupported after deletes/updates

ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2255

ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2461

Page 14: Materialized Views.docx

ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2430

ORA-06512: at line 1

 

This time we received an error when we attempted a fast refresh. The reason is because this type of materialized view is an "insert-only" materialized view, i.e. it is only fast refreshable for inserts and direct loads, not updates or deletes. (We will see why it is an insert-only view in the next topic, DBMS_MVIEW.EXPLAIN_MVIEW.) To synchronize an insert-only materialized view after a delete we need to do a complete refresh.

execute dbms_mview.refresh( list => 'MV', method => 'C' );

select rowid, t_key, amt_max from mv ;

 

ROWID T_KEY AMT_MAX

------------------ ---------- ----------

AAAhMzAAEAAAEG8AAC 1 300

AAAhMzAAEAAAEG8AAD 2 250

 

Restrictions on Fast Refresh

So how do we know whether a materialized view can be fast refreshed each time, sometimes, or never? One way would be to learn all the documented restrictions for fast refreshable materialized views. Here are some of them.

In general materialized views cannot be fast refreshed if the base tables do not have materialized view logs or the defining query:

contains an analytic function

Page 15: Materialized Views.docx

contains non-repeating expressions like SYSDATE or ROWNUM contains RAW or LONG RAW data types contains a subquery in the SELECT clause contains a MODEL clause contains a HAVING clause contains nested queries with ANY, ALL, or NOT EXISTS contains a CONNECT BY clause references remote tables in different databases references remote tables in a single database and defaults to the ON

COMMIT refresh mode references other materialized views which are not join or aggregate

materialized views.There are even more restrictions for materialized views containing joins, aggregates, UNION ALL, subqueries, etc. They are documented in various sections of a few different manuals and are too numerous and complex to repeat here. The following links can help you find them if required though.

CREATE MATERIALIZED VIEW - FAST Clause General Restrictions on Fast Refresh Restrictions on Fast Refresh on Materialized Views with Joins Only Restrictions on Fast Refresh on Materialized Views with Aggregates Restrictions on Fast Refresh on Materialized Views with UNION ALL Restrictions for Materialized Views with Subqueries Restrictions for Materialized Views with Unions Containing Subqueries Restrictions for Using Multitier Materialized Views Restrictions for Materialized Views with Collection Columns

Fortunately there is a second, simpler alternative for determining whether a materialized view is fast refreshable or not. It uses the DBMS_MVIEW.EXPLAIN_MVIEW utility which we will explore next.

Cleanup

drop materialized view mv ;

drop materialized view log on t2 ;

Materialized Views

Page 16: Materialized Views.docx

DBMS_MVIEW.EXPLAIN_MVIEW

As we saw in the preceding topic, predicting whether or not a materialized view is fast refreshable can be complicated. TheDBMS_MVIEW.EXPLAIN_MVIEW utility can simplify this task however. Full details on how the utility works are available at the preceding link. The material below will help you use the utility effectively.

MV_CAPABILITIES_TABLE

There are two ways to get the output from DBMS_MVIEW.EXPLAIN_MVIEW, via a table or via a varray. To use the table method the current schema must contain a table called MV_CAPABILITIES_TABLE. The full, documented CREATE TABLE command for MV_CAPABILITIES_TABLE can be found on UNIX systems at $ORACLE_HOME/rdbms/admin/utlxmv.sql. It is also available in Oracle's documentation at Oracle Database Data Warehousing Guide - Basic Materialized Views - Using MV_CAPABILITIES_TABLE (see Gotchafor a related bug). Here is an abridged version.

create table MV_CAPABILITIES_TABLE

(

statement_id varchar(30) ,

mvowner varchar(30) ,

mvname varchar(30) ,

capability_name varchar(30) ,

possible character(1) ,

related_text varchar(2000) ,

related_num number ,

msgno integer ,

msgtxt varchar(2000) ,

seq number

Page 17: Materialized Views.docx

) ;

 

VARRAY Output

Using DBMS_MVIEW.EXPLAIN_MVIEW with the table output method typically involves

1.deleting old rows from MV_CAPABILITIES_TABLE2.running DBMS_MVIEW.EXPLAIN_MVIEW3.selecting new rows from MV_CAPABILITIES_TABLE.

To save time in this tutorial we will use DBMS_MVIEW.EXPLAIN_MVIEW's varray output option instead and supplement it with a custom function called MY_MV_CAPABILITIES.

create or replace function my_mv_capabilities

(

p_mv in varchar2 ,

p_capability_name_filter in varchar2 default '%' ,

p_include_pct_capabilities in varchar2 default 'N' ,

p_linesize in number default 80

)

return clob

as

--------------------------------------------------------------------------------

-- From http://www.sqlsnippets.com/en/topic-12884.html

--

-- Parameters:

--

Page 18: Materialized Views.docx

-- p_mv

-- o this value is passed to DBMS_MVIEW.EXPLAIN_MVIEW's "mv" parameter

-- o it can contain either a query, CREATE MATERIALIZED VIEW command text,

-- or a materialized view name

--

-- p_capability_name_filter

-- o use either REFRESH, REWRITE, PCT, or the default

--

-- p_include_pct_capabilities

-- Y - capabilities like REFRESH_FAST_PCT are included in the report

-- N - capabilities like REFRESH_FAST_PCT are not included in the report

--

-- p_linesize

-- o the maximum size allowed for any line in the report output

-- o data that is longer than this value will be word wrapped

--

-- Typical Usage:

--

-- set long 5000

-- select my_mv_capabilities( 'MV_NAME' ) as mv_report from dual ;

--

-- o the value 5000 is arbitraty; any value big enough to contain the

-- report output will do

--

--------------------------------------------------------------------------------

Page 19: Materialized Views.docx

pragma autonomous_transaction ;

v_nl constant char(1) := unistr( '\000A' ); -- new line

v_previous_possible char(1) := 'X' ;

v_capabilities sys.ExplainMVArrayType ;

v_output clob ;

begin

dbms_mview.explain_mview( mv => p_mv, msg_array => v_capabilities ) ;

for v_capability in

(

select

capability_name ,

possible ,

related_text ,

msgtxt

from

table( v_capabilities )

where

Page 20: Materialized Views.docx

capability_name like '%' || upper( p_capability_name_filter ) || '%' and

not

( capability_name like '%PCT%' and

upper(p_include_pct_capabilities) = 'N'

)

order by

mvowner ,

mvname ,

possible desc ,

seq

)

loop

------------------------------------------------------------

-- print section heading

------------------------------------------------------------

if v_capability.possible <> v_previous_possible then

v_output :=

v_output

|| v_nl

|| case v_capability.possible

when 'T' then 'Capable of: '

when 'Y' then 'Capable of: '

Page 21: Materialized Views.docx

when 'F' then 'Not Capable of: '

when 'N' then 'Not Capable of: '

else v_capability.possible || ':'

end

|| v_nl

;

end if;

v_previous_possible := v_capability.possible ;

------------------------------------------------------------

-- print section body

------------------------------------------------------------

declare

v_indented_line_size varchar2(3) := to_char( p_linesize - 5 );

begin

-- print capability name indented 2 spaces

v_output :=

v_output

|| v_nl

Page 22: Materialized Views.docx

|| ' '

|| v_capability.capability_name

|| v_nl

;

-- print related text indented 4 spaces and word wrapped

if v_capability.related_text is not null then

v_output :=

v_output

|| regexp_replace

( v_capability.related_text || ' '

, '(.{1,'

|| v_indented_line_size || '} |.{1,'

|| v_indented_line_size || '})'

, ' \1' || v_nl

)

;

end if;

-- print message text indented 4 spaces and word wrapped

if v_capability.msgtxt is not null then

Page 23: Materialized Views.docx

v_output :=

v_output

|| regexp_replace

( v_capability.msgtxt || ' '

, '(.{1,'

|| v_indented_line_size || '} |.{1,'

|| v_indented_line_size || '})'

, ' \1' || v_nl

)

;

end if;

end;

end loop;

commit ;

return( v_output );

end;

/

Page 24: Materialized Views.docx

show errors

No errors.

 

This completes our preparations. Now let's see DBMS_MVIEW.EXPLAIN_VIEW in action.

DBMS_MVIEW.EXPLAIN_MVIEW With a Query

DBMS_MVIEW.EXPLAIN_MVIEW can analyze three different types of materialized view code:

1.a defining query2.a CREATE MATERIALIZED VIEW command3.an existing materialized view.

Here is an example that explains a simple query which could appear as the defining query in a CREATE MATERIALIZED VIEW command.

set long 5000

select my_mv_capabilities( 'SELECT * FROM T', 'REFRESH' ) as mv_report from dual ;

 

MV_REPORT

--------------------------------------------------------------------------------

Capable of:

REFRESH_COMPLETE

Not Capable of:

Page 25: Materialized Views.docx

REFRESH_FAST

REFRESH_FAST_AFTER_INSERT

SCOTT.T

the detail table does not have a materialized view log

REFRESH_FAST_AFTER_ONETAB_DML

see the reason why REFRESH_FAST_AFTER_INSERT is disabled

REFRESH_FAST_AFTER_ANY_DML

see the reason why REFRESH_FAST_AFTER_ONETAB_DML is disabled

 

(Descriptions of each capability name are available at Table 8-7 CAPABILITY_NAME Column Details. A list of messages and related text is available at Table 8-8 MV_CAPABILITIES_TABLE Column Details.)

The EXPLAIN_MVIEW output above shows that fast refresh is not possible in this case because T has no materialized view log.

Note that DBMS_MVIEW.EXPLAIN_MVIEW can report on a materialized view's refresh, rewrite, and partition change tracking (PCT) capabilities. For now we will only examine refresh capabilities. Rewrite capabilities will be covered in Query Rewrite Restrictions and Capabilities.

DBMS_MVIEW.EXPLAIN_MVIEW With CREATE MATERIALIZED VIEW

Now let's create a materialized view log on T and then use EXPLAIN_MVIEW to explain the capabilities of an entire CREATE MATERIALIZED VIEW command.

create materialized view log on t ;

Page 26: Materialized Views.docx

select

my_mv_capabilities

( 'CREATE MATERIALIZED VIEW MV REFRESH FAST AS SELECT * FROM T'

, 'REFRESH'

) as mv_report

from dual ;

 

MV_REPORT

--------------------------------------------------------------------------------

Capable of:

REFRESH_COMPLETE

REFRESH_FAST

REFRESH_FAST_AFTER_INSERT

REFRESH_FAST_AFTER_ONETAB_DML

REFRESH_FAST_AFTER_ANY_DML

 

This time we see that a materialized view using our simple query could be fast refreshable in all cases.

Page 27: Materialized Views.docx

DBMS_MVIEW.EXPLAIN_MVIEW With Existing Materialized View

For our last example we will explain an existing materialized view, the insert-only one we saw in the preceding topic REFRESH FAST Categories.

create materialized view log on t2

with primary key, rowid, sequence ( t_key, amt )

including new values

;

create materialized view mv

refresh fast

as

select t_key, max( amt ) amt_max

from t2

group by t_key

;

select my_mv_capabilities( 'MV', 'REFRESH' ) as mv_report from dual ;

 

MV_REPORT

--------------------------------------------------------------------------------

Capable of:

REFRESH_COMPLETE

Page 28: Materialized Views.docx

REFRESH_FAST

REFRESH_FAST_AFTER_INSERT

Not Capable of:

REFRESH_FAST_AFTER_ONETAB_DML

mv uses the MIN or MAX aggregate functions

REFRESH_FAST_AFTER_ONETAB_DML

COUNT(*) is not present in the select list

REFRESH_FAST_AFTER_ANY_DML

see the reason why REFRESH_FAST_AFTER_ONETAB_DML is disabled

 

Here we see that fast refresh is available after inserts, but not other types of DML. Note also that the "REFRESH_FAST" capability will appear whenever at least one of the other REFRESH_FAST_% capabilities is available. It does not mean the materialized view is fast refreshable in all cases.

Gotcha

Both the $ORACLE_HOME/rdbms/admin/utlxmv.sql file and the CREATE TABLE command at Oracle Database Data Warehousing Guide - Basic Materialized Views - Using MV_CAPABILITIES_TABLE state the values in MV_CAPABILITIES_TABLE.POSSIBLE will either be "T" or "F".

CREATE TABLE MV_CAPABILITIES_TABLE

...

POSSIBLE CHARACTER(1), -- T = capability is possible

Page 29: Materialized Views.docx

-- F = capability is not possible

...

 

In actual use we can see the values are really "Y" and "N".

delete from mv_capabilities_table ;

execute dbms_mview.explain_mview( 'select * from t' );

commit;

column possible format a8

select distinct POSSIBLE from mv_capabilities_table ;

 

POSSIBLE

--------

Y

N

 

The values "T" and "F" are, however, used when DBMS_MVIEW.EXPLAIN_MVIEW output is saved to a varray.

Cleanup

set long 80

Page 30: Materialized Views.docx

drop materialized view mv ;

drop materialized view log on t ;

drop materialized view log on t2 ;

 

Materialized Views

REFRESH FORCE

In REFRESH FAST Categories and DBMS_MVIEW.EXPLAIN_MVIEW we saw an insert-only materialized view which could be fast refreshed after inserts into the base table but needed a complete refresh after other types of DML. With these types of materialized views it is often most convenient to let Oracle decide which refresh method is best. The REFRESH FORCE method does just that. It performs a FAST refresh if possible, otherwise it performs a COMPLETE refresh.

create materialized view log on t2

with primary key, rowid, sequence ( t_key, amt )

including new values

;

create materialized view mv

REFRESH FORCE

as

select t_key, max( amt ) amt_max

from t2

group by t_key

Page 31: Materialized Views.docx

;

select rowid, t_key, amt_max from mv ;

 

ROWID T_KEY AMT_MAX

------------------ ---------- ----------

AAAWpLAAEAAAAaMAAA 1 300

AAAWpLAAEAAAAaMAAB 2 250

 

First let's try an insert and a refresh.

insert into t2 values ( 5, 2, 500 );

commit;

execute dbms_mview.refresh( list => 'MV' );

select rowid, t_key, amt_max from mv ;

 

ROWID T_KEY AMT_MAX

------------------ ---------- ----------

AAAWpLAAEAAAAaMAAA 1 300

AAAWpLAAEAAAAaMAAB 2 500

 

Since the rowids did not change but the AMT_MAX values did we can tell that a FAST refresh was performed. Now let's try a delete followed by a refresh.

Page 32: Materialized Views.docx

delete from t2 where key = 5 ;

commit;

execute dbms_mview.refresh( list => 'MV' );

select rowid, t_key, amt_max from mv ;

 

ROWID T_KEY AMT_MAX

------------------ ---------- ----------

AAAWpLAAEAAAAaMAAC 1 300

AAAWpLAAEAAAAaMAAD 2 250

 

In the REFRESH FAST Categories topic we received an "ORA-32314: REFRESH FAST of "SCOTT"."MV" unsupported after deletes/updates" error at this point. This time with REFRESH FORCE we did not. Instead Oracle performed a COMPLETE refresh (note how the rowids for each row changed).

Cleanup

drop materialized view mv ;

drop materialized view log on t2 ;

 

Materialized Views

NEVER REFRESH

Page 33: Materialized Views.docx

If for some reason we need to prevent refresh operations of any sort, FAST or COMPLETE, on our materialized views we can use theNEVER REFRESH method.

create materialized view mv

NEVER REFRESH

as select * from t

;

select * from mv ;

 

KEY VAL

---------- -----

1 a

2 b

3 c

4

 

Let's see what happens when we update the base table and then attempt a refresh.

update t set val = upper(val) ;

commit ;

execute dbms_mview.refresh( 'MV' );

BEGIN dbms_mview.refresh( 'MV' ); END;

Page 34: Materialized Views.docx

*

ERROR at line 1:

ORA-23538: cannot explicitly refresh a NEVER REFRESH materialized view ("MV")

ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2537

ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2743

ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2712

ORA-06512: at line 1

 

Oracle prevented the refresh by raising an error.

I cannot see a practical reason for having a materialized view with NEVER REFRESH set at all times. (If you know of any please let me know using the Comments link below.) NEVER REFRESH can come in handy though when refresh operations on a materialized view need to be prevented temporarily during maintenance or debugging operations. In this case the materialized view's refresh mode can be changed to NEVER REFRESH using the ALTER MATERIALIZED VIEW command.

Cleanup

drop materialized view mv ;

update t set val = lower(val) ;

commit ;

 

Materialized Views

Page 35: Materialized Views.docx

ON DEMAND

Up to this point in the tutorial we have always refreshed our materialized views manually with the DBMS_MVIEW.REFRESH command. This is know as ON DEMAND refreshing and it is the default refresh mode when none is specified in the CREATE MATERIALIZED VIEW command. In other words this

create materialized view mv

as select * from t

;

 

is equivalent to this.

drop materialized view mv ;

create materialized view mv

REFRESH ON DEMAND

as select * from t

;

 

To refresh ON DEMAND materialized views we explicitly call one of the following procedures.

DBMS_MVIEW.REFRESH DBMS_MVIEW.REFRESH_ALL_MVIEWS DBMS_MVIEW.REFRESH_DEPENDENT

Here is an example that uses DBMS_MVIEW.REFRESH.

insert into t values ( 5, 'e' );

Page 36: Materialized Views.docx

commit;

 

select * from mv where key = 5 ;

no rows selected

 

execute DBMS_MVIEW.REFRESH( 'MV' );

select * from mv where key = 5 ;

 

KEY VAL

---------- -----

5 e

 

Cleanup

drop materialized view mv ;

delete from t where key = 5 ;

commit;

 

Materialized Views

ON COMMIT

Page 37: Materialized Views.docx

In some situations it would be convenient to have Oracle refresh a materialized view automatically whenever changes to the base table are committed. This is possible using the ON COMMIT refresh mode. Here is an example.

create materialized view log on t ;

create materialized view mv

REFRESH FAST ON COMMIT

as select * from t

;

select rowid, key, val from mv ;

 

ROWID KEY VAL

------------------ ---------- -----

AAAXNGAAEAAAAasAAA 1 a

AAAXNGAAEAAAAasAAB 2 b

AAAXNGAAEAAAAasAAC 3 c

AAAXNGAAEAAAAasAAD 4

 

Let's see what happens to the view in the course of an insert operation.

insert into t values ( 5, 'e' );

select rowid, key, val from mv ;

 

Page 38: Materialized Views.docx

ROWID KEY VAL

------------------ ---------- -----

AAAXNGAAEAAAAasAAA 1 a

AAAXNGAAEAAAAasAAB 2 b

AAAXNGAAEAAAAasAAC 3 c

AAAXNGAAEAAAAasAAD 4

 

Nothing happend yet. Let's issue a COMMIT.

commit;

select rowid, key, val from mv ;

 

ROWID KEY VAL

------------------ ---------- -----

AAAXNGAAEAAAAasAAA 1 a

AAAXNGAAEAAAAasAAB 2 b

AAAXNGAAEAAAAasAAC 3 c

AAAXNGAAEAAAAasAAD 4

AAAXNGAAEAAAAatAAA 5 e

 

Note how the materialized view was automatically fast refreshed after the COMMIT command. No call to DBMS_MVIEW.REFRESH was required.

Restrictions

Materialized views can only refresh ON COMMIT in certain situations.

Page 39: Materialized Views.docx

1. The materialized view cannot contain object types or Oracle-supplied types.

2. The base tables will never have any distributed transactions applied to them.

The first case produces an error during the CREATE MATERIALIZED VIEW command.

-- this materialized view is not fast refreshable

-- because the materialized view contains an Oracle-supplied type

create materialized view mv2

REFRESH FAST ON COMMIT

as select key, val, sys_xmlgen( val ) as val_xml from t

;

as select key, val, sys_xmlgen( val ) as val_xml from t

*

ERROR at line 3:

ORA-12054: cannot set the ON COMMIT refresh attribute for the materialized view

 

The second case generates an error when a distributed transaction is attempted on the base table. In the following example materialized view MV (created at the top of this page) was created with REFRESH FAST. Attempting a distributed transaction on its base table, T, will therefore raise an error.

insert into t select key+10, val from T@REMOTE ;

commit;

commit

*

Page 40: Materialized Views.docx

ERROR at line 1:

ORA-02050: transaction 5.21.5632 rolled back, some remote DBs may be in-doubt

ORA-02051: another session in same transaction failed

 

(REMOTE is a database link which loops back to the current account.)

ON DEMAND materialized views have no such restriction, as the following snippet demonstrates.

alter materialized view mv refresh ON DEMAND ;

insert into t select key+10, val from T@REMOTE ;

commit;

select * from t ;

 

KEY VAL

---------- -----

1 a

2 b

3 c

4

5 e

11 a

12 b

Page 41: Materialized Views.docx

13 c

14

15 e

 

-- cleanup test data in preparation for next section

delete from t where key >= 5 ;

commit ;

 

Gotcha

The SQL Language Reference manual says this about the ON COMMIT clause.

"Specify ON COMMIT to indicate that a fast refresh is to occur whenever the database commits a transaction that operates on a master table of the materialized view." -- Oracle® Database SQL Language Reference: CREATE MATERIALIZED VIEW

When I first read this I assumed it meant that "REFRESH COMPLETE ON COMMIT" is not allowed. I also assumed that specifying "REFRESH ON COMMIT" is equivalent to specifying "REFRESH FAST ON COMMIT". The following examples prove neither is correct however.

create materialized view mv2

REFRESH COMPLETE ON COMMIT

as select key, val from t

;

 

Page 42: Materialized Views.docx

As we can see the CREATE MATERIALZIED view command succeeded even though COMPLETE, not FAST, was specified with ON COMMIT. The next example examines the behavior of "REFRESH ON COMMIT" without a specified refresh method.

drop materialized view log on t ;

-- fast refreshable materialized views on T can no longer be created on T

-- because it has no materialized view log

drop materialized view mv2 ;

create materialized view mv2

REFRESH ON COMMIT

as select key, val from t

;

select rowid, key, val from mv2 ;

 

ROWID KEY VAL

------------------ ---------- -----

AAAXNMAAEAAAAakAAA 1 a

AAAXNMAAEAAAAakAAB 2 b

AAAXNMAAEAAAAakAAC 3 c

AAAXNMAAEAAAAakAAD 4

 

insert into t values ( 5, 'e' );

Page 43: Materialized Views.docx

commit ;

select rowid, key, val from mv2 ;

 

ROWID KEY VAL

------------------ ---------- -----

AAAXNMAAEAAAAakAAE 1 a

AAAXNMAAEAAAAakAAF 2 b

AAAXNMAAEAAAAakAAG 3 c

AAAXNMAAEAAAAakAAH 4

AAAXNMAAEAAAAakAAI 5 e

 

The fact that all the rowid's in MV2 changed after the INSERT transaction committed confirms that a complete refresh took place during the commit. "REFRESH ON COMMIT" is not therefore equivalent to "REFRESH FAST ON COMMIT". In fact, when no REFRESH method is specified the default behaviour is "REFRESH FORCE" regardless of whether ON COMMIT is used or not.

Given these observations I can only conclude the documentation is either in error or misleading when it says "specify ON COMMIT to indicate that a fast refresh is to occur".

Cleanup

drop materialized view mv ;

drop materialized view mv2 ;

Page 44: Materialized Views.docx

delete from t where key >= 5 ;

commit ;

 

Materialized Views

Constraints

System Generated Constraints

When a materialized view is created Oracle may add system generated constraints to its underlying table (i.e. the table containing the results of the query, not to be confused with a base table). In the following example note how Oracle automatically adds a primary key constraint to the table called "MV", which is part of the materialized view also called "MV".

create materialized view mv

as select key, val from t

;

column constraint_name format a20

column constraint_type format a15

column index_name format a15

select constraint_name, constraint_type, index_name

from user_constraints

where TABLE_NAME = 'MV' ;

 

CONSTRAINT_NAME CONSTRAINT_TYPE INDEX_NAME

Page 45: Materialized Views.docx

-------------------- --------------- ---------------

SYS_C0019948 P SYS_C0019948

 

In the next example Oracle automatically adds a check constraint.

drop materialized view mv ;

describe t2

Name Null? Type

-------------------------------------------- -------- ------------------------------

KEY NOT NULL NUMBER

T_KEY NOT NULL NUMBER

AMT NOT NULL NUMBER

create materialized view log on t2

with primary key, rowid, sequence ( t_key, amt )

including new values

;

create materialized view mv

refresh fast on commit

as

select t_key, count(*) row_count

from t2

group by t_key

Page 46: Materialized Views.docx

;

column search_condition format a30

select constraint_name, constraint_type, search_condition

from user_constraints

where table_name = 'MV' ;

 

CONSTRAINT_NAME CONSTRAINT_TYPE SEARCH_CONDITION

-------------------- --------------- ------------------------------

SYS_C0019949 C "T_KEY" IS NOT NULL

 

Adding Your Own Constraints

If necessary we can create our own constraints on materialized view tables in addition to the ones Oracle may add. When the materialized view is in ON COMMIT mode these constraints effectively constrain the materialized view's base tables. Let's see this in action by creating a check constraint on MV.

select * from t2 ;

 

KEY T_KEY AMT

---------- ---------- ----------

10 1 100

20 1 300

30 1 200

40 2 250

Page 47: Materialized Views.docx

50 2 150

 

alter table mv -- note we used "alter table" here

add CONSTRAINT MY_CONSTRAINT CHECK ( ROW_COUNT <= 3 ) DEFERRABLE

;

select constraint_name, constraint_type, search_condition

from user_constraints

where table_name = 'MV' ;

 

CONSTRAINT_NAME CONSTRAINT_TYPE SEARCH_CONDITION

-------------------- --------------- ------------------------------

SYS_C0019949 C "T_KEY" IS NOT NULL

MY_CONSTRAINT C ROW_COUNT <= 3

 

Now any attempt to create more than 3 rows per group in table T2 will generate an error at commit time.

insert into T2 values ( 5, 1, 500 );

commit;

commit

*

ERROR at line 1:

ORA-12008: error in materialized view refresh path

ORA-02290: check constraint (SCOTT.MY_CONSTRAINT) violated

Page 48: Materialized Views.docx

 

Implementing multirow validation rules such as this one properly is not possible using check constraints on regular tables. Implementing them using triggers can be difficult if not impossible. With materialized views they are declared using a few lines of code and are virtually bullet proof when applied correctly. We will learn more about this powerful multirow validation approach in a future SQL Snippets tutorial so stay tuned! In the mean time Ask Tom "Declarative Integrity" has some good information on the subject.

Gotcha

When we created MY_CONSTRAINT above we use an ALTER TABLE command. Curiously enough an ALTER MATERIALIZED VIEW command would have worked too.

ALTER MATERIALIZED VIEW mv

add constraint my_second_constraint check ( row_count < 4 ) deferrable

;

select constraint_name, constraint_type, search_condition

from user_constraints

where table_name = 'MV' ;

 

CONSTRAINT_NAME CONSTRAINT_TYPE SEARCH_CONDITION

-------------------- --------------- ------------------------------

SYS_C0019949 C "T_KEY" IS NOT NULL

MY_CONSTRAINT C ROW_COUNT <= 3

Page 49: Materialized Views.docx

MY_SECOND_CONSTRAINT C row_count < 4

 

The Oracle manual page for ALTER MATERIALIZED VIEW however does not indicate that constraints can be added this way. Until the documentation says this is legal it is best to use ALTER TABLE.

Cleanup

drop materialized view mv ;

drop materialized view log on t2 ;

 

Materialized Views

Indexes

When a materialized view is created Oracle may add system generated indexes to its underlying table (i.e. the table containing the results of the query, not to be confused with a base table). In the following example note how Oracle automatically adds an index to implement the system generated primary key we saw in the preceding topic, Constraints.

create materialized view mv

as select key, val from t

;

column index_name format a15

column column_name format a15

select

Page 50: Materialized Views.docx

index_name ,

i.uniqueness ,

ic.column_name

from

user_indexes i

inner join user_ind_columns ic

using ( index_name )

where

i.table_name = 'MV'

;

 

INDEX_NAME UNIQUENES COLUMN_NAME

--------------- --------- ---------------

SYS_C0019959 UNIQUE KEY

 

In the next example Oracle automatically generates a function based index.

drop materialized view mv ;

create materialized view log on t2

with primary key, rowid, sequence ( t_key, amt )

including new values

;

create materialized view mv

Page 51: Materialized Views.docx

refresh fast on commit

as

select t_key, COUNT(*) ROW_COUNT

from t2

group by t_key

;

column column_expression format a35

select

index_name ,

i.uniqueness ,

ic.column_name ,

ie.column_expression

from

user_indexes i

inner join user_ind_columns ic

left outer join user_ind_expressions ie

using ( index_name )

using ( index_name )

where

ic.table_name = 'MV'

;

 

INDEX_NAME UNIQUENES COLUMN_NAME COLUMN_EXPRESSION

Page 52: Materialized Views.docx

--------------- --------- --------------- -----------------------------------

I_SNAP$_MV UNIQUE SYS_NC00003$ SYS_OP_MAP_NONNULL("T_KEY")

 

(Note that SYS_OP_MAP_NONNULL is an undocumented Oracle function. Do not attempt to use it in your own code. See Nulls and Equality: SQL Only for additional info.)

Adding Your Own Indexes

We can add out own indexes to MV just as we would a regular table. In the following example we will add an index on the T_KEY column.

create index MY_INDEX on mv ( T_KEY ) ;

select

index_name ,

i.uniqueness ,

ic.column_name

from

user_indexes i

inner join user_ind_columns ic

using ( index_name )

where

i.table_name = 'MV'

;

 

INDEX_NAME UNIQUENES COLUMN_NAME

--------------- --------- ---------------

Page 53: Materialized Views.docx

I_SNAP$_MV UNIQUE SYS_NC00003$

MY_INDEX NONUNIQUE T_KEY

 

To confirm that Oracle uses our index in queries let's turn SQL*Plus's Autotrace feature on and execute a query.

set autotrace on explain

set linesize 95

select *

from mv

where t_key = 2 ;

T_KEY ROW_COUNT

---------- ----------

2 2

Execution Plan

----------------------------------------------------------

Plan hash value: 2793437614

-------------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

-------------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 26 | 2 (0)| 00:00:01 |

| 1 | MAT_VIEW ACCESS BY INDEX ROWID| MV | 1 | 26 | 2 (0)| 00:00:01 |

|* 2 | INDEX RANGE SCAN | MY_INDEX | 1 | | 1 (0)| 00:00:01 |

-------------------------------------------------------------------------------------------

Page 54: Materialized Views.docx

Predicate Information (identified by operation id):

---------------------------------------------------

2 - access("T_KEY"=2)

Note

-----

- dynamic sampling used for this statement

 

Note how the optimizer chose an INDEX RANGE SCAN from MY_INDEX in step 2.

Cleanup

drop materialized view mv ;

drop materialized view log on t2 ;

 

Materialized Views

ENABLE QUERY REWRITE

Materialized views can be useful for pre-calculating and storing derived values such as AMT_MAX in the following snippet.

create materialized view log on t2

with primary key, rowid, sequence ( t_key, amt )

including new values

;

Page 55: Materialized Views.docx

create materialized view mv

refresh fast on commit

as

select t_key, MAX( AMT ) AMT_MAX

from t2

group by t_key

;

 

Such materialized views make queries like this

select t_key, amt_max

FROM MV

order by t_key ;

 

T_KEY AMT_MAX

---------- ----------

1 300

2 250

 

faster than its equivalent query.

select t_key, max( amt ) as amt_max

Page 56: Materialized Views.docx

FROM T2

group by t_key

order by t_key ;

 

T_KEY AMT_MAX

---------- ----------

1 300

2 250

 

Wouldn't it be nice if Oracle could use the information in MV to resolve this last query too? If your database has a feature called Query Rewrite available and enabled this happens automatically. To see it in action we first need to make the materialized view available to Query Rewrite like this.

alter materialized view mv ENABLE QUERY REWRITE ;

 

(See Gotcha - ORA-00439 below if you encounter an ORA-00439 error at this step.)

Note that materialized views which do not include the ENABLE QUERY REWRITE clause will have Query Rewrite disabled by default.

Next we collect statistics on the materialized view to help Oracle optimize the query rewrite process.

execute dbms_stats.gather_table_stats( user, 'MV' ) ;

 

Page 57: Materialized Views.docx

Finally we can confirm Oracle will use the materialized view in queries by turning SQL*Plus's Autotrace feature on.

set autotrace on explain

set linesize 95

select t_key, max( amt ) as amt_max

FROM T2

group by t_key

order by t_key ;

T_KEY AMT_MAX

---------- ----------

1 300

2 250

Execution Plan

----------------------------------------------------------

Plan hash value: 446852971

--------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 2 | 14 | 4 (25)| 00:00:01 |

| 1 | SORT ORDER BY | | 2 | 14 | 4 (25)| 00:00:01 |

| 2 | MAT_VIEW REWRITE ACCESS FULL| MV | 2 | 14 | 3 (0)| 00:00:01 |

--------------------------------------------------------------------------------------

 

Page 58: Materialized Views.docx

Note how the optimizer chose to access MV for its pre-calculated MAX(AMT) values in line 2 even though the query itself made no mention of MV. Without the Query Rewrite feature the execution plan would look like this.

alter session set QUERY_REWRITE_ENABLED = FALSE ;

select t_key, max( amt ) as amt_max

FROM T2

group by t_key

order by t_key ;

T_KEY AMT_MAX

---------- ----------

1 300

2 250

Execution Plan

----------------------------------------------------------

Plan hash value: 50962384

---------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

---------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 5 | 130 | 4 (25)| 00:00:01 |

| 1 | SORT GROUP BY | | 5 | 130 | 4 (25)| 00:00:01 |

| 2 | TABLE ACCESS FULL| T2 | 5 | 130 | 3 (0)| 00:00:01 |

---------------------------------------------------------------------------

Note

-----

Page 59: Materialized Views.docx

- dynamic sampling used for this statement

 

Note how the optimizer chose to access T2 this time. Each time this query is executed it has to re-calculate MAX(VAL) from the information in T2 for each group, a more expensive approach than simply selecting pre-calculated column values from MV is.

Gotcha - ORA-00439

The materialized view query rewrite feature is not available in Oracle XE and some other Oracle configurations. If you attempt to use ENABLE QUERY REWITE in an Oracle database where the feature is not enabled you will receive an ORA-00439 error.

create materialized view mv2

refresh fast on commit

ENABLE QUERY REWRITE

as

select

t_key ,

count(*) as row_count ,

count(amt) as amt_count

from t2

group by t_key

;

from t2

*

ERROR at line 9:

ORA-00439: feature not enabled: Materialized view rewrite

 

Page 60: Materialized Views.docx

Cleanup

alter session set query_rewrite_enabled = true ;

set autotrace off

drop materialized view mv ;

drop materialized view log on t2 ;

Materialized Views

Query Rewrite Restrictions and Capabilities

Restrictions

Materialized views with the following characteristics cannot have query rewrite enabled:

the defining query references functions which are not DETERMINISTIC an expression in the defining query is not repeatable; e.g. an expression

containing the USER pseudo column or the SYSTIMESTAMP function.Attempting to violate these restrictions results in an error.

create materialized view mv

ENABLE QUERY REWRITE

as select key, val, USER from t

;

as select key, val, USER from t

*

ERROR at line 3:

Page 61: Materialized Views.docx

ORA-30353: expression not supported for query rewrite

 

Capabilities

A few different materialized view query rewrite capabilities exist. In EXPLAIN_MVIEW we used a utility called MY_MV_CAPABILITIES to explore a materialized view's refresh capabilities. In the snippets below we will use this same utility to explore rewrite capabilities.

First lets look at a simple, single table materialized view with query rewrite disabled.

create materialized view mv

DISABLE QUERY REWRITE

as select key, val from t

;

set long 5000

select my_mv_capabilities( 'MV', 'REWRITE' ) as mv_report from dual ;

 

MV_REPORT

--------------------------------------------------------------------------------

Not Capable of:

Page 62: Materialized Views.docx

REWRITE

REWRITE_FULL_TEXT_MATCH

query rewrite is disabled on the materialized view

REWRITE_PARTIAL_TEXT_MATCH

query rewrite is disabled on the materialized view

REWRITE_GENERAL

query rewrite is disabled on the materialized view

 

This materialized view obviously has no rewrite capabilities available to it. (Descriptions of each capability name are available at Table 8-7 CAPABILITY_NAME Column Details.)

Enabling query rewrite on the materialized view changes this.

alter materialized view mv ENABLE QUERY REWRITE ;

select my_mv_capabilities( 'MV', 'REWRITE' ) as mv_report from dual ;

 

MV_REPORT

--------------------------------------------------------------------------------

Capable of:

REWRITE

Page 63: Materialized Views.docx

REWRITE_FULL_TEXT_MATCH

REWRITE_PARTIAL_TEXT_MATCH

REWRITE_GENERAL

 

Now all rewrite capabilities are available. If the materialized view happened to referenced a remote table then some rewrite capabilities would be available, but not others.

drop materialized view mv ;

create materialized view mv

enable query rewrite

as select key, val from T@REMOTE

;

select my_mv_capabilities( 'MV', 'REWRITE' ) as mv_report from dual ;

 

MV_REPORT

--------------------------------------------------------------------------------

Capable of:

REWRITE

Page 64: Materialized Views.docx

REWRITE_PARTIAL_TEXT_MATCH

REWRITE_GENERAL

Not Capable of:

REWRITE_FULL_TEXT_MATCH

T

mv references a remote table or view in the FROM list

 

Cleanup

drop materialized view mv ;