This was first published on https://blog.dbi-services.com/ocm-12c-preparation-explain-fast-refresh (2015-12-17)
Republishing here for new followers. The content is related to the the versions available at the publication date

OCM 12c preparation: Explain fast refresh

There are some rules to be able to fast refresh a materialized view (which means, refresh it so that it is not stale, and without running the whole query). Documentation is in the Datawarehouse Guide, but we can use Enterprise Manager to get quickly to our goal.

Let’s see which tables we have:

CaptureMV001

and create materialized views:

CaptureMV002

I want to materialize the following join and group by:

select deptno,dname,count(*),sum(sal)
from scott.dept join scott.emp using (deptno)
group by deptno,dname
when entering the query you can run ‘explain':

CaptureMV003

here is what is displayed by the explain

CaptureMV004

For fast refresh we need materialized view log, so let’s create them:

CaptureMV005

I keep the default: primary key and choose the other column I will use in my materialized view:

CaptureMV006

I do it for both tables, here is what ‘show sql’ displays:

CREATE MATERIALIZED VIEW LOG ON SCOTT.DEPT NOCACHE WITH PRIMARY KEY ("DNAME") EXCLUDING NEW VALUES
CREATE MATERIALIZED VIEW LOG ON SCOTT.EMP NOCACHE WITH PRIMARY KEY ("DEPTNO", "SAL") EXCLUDING NEW VALUES
Note that there is no comma between the with clause and the column list. If you put one, you can have strange behaviour.

so here they are:

CaptureMV007

and let’s explain our mview again:

CaptureMV008

In order to support fast refresh for all kind of DML, I need to add the following ‘with’ clause:

ALTER MATERIALIZED VIEW LOG ON DEPT ADD SEQUENCE, ROWID INCLUDING NEW VALUES;
ALTER MATERIALIZED VIEW LOG ON EMP ADD SEQUENCE, ROWID INCLUDING NEW VALUES;
You can do it from the GUI, but I don’t want to navigate though screens again.

So the result is that my materialized view supports fast refresh. But there was something else:

CaptureMV012

In order to maintain the SUM() and because the SAL column may be null, we need to keep a count of non null values.

select deptno,dname,count(*),sum(sal),count(sal)
from scott.dept join scott.emp using (deptno)
group by deptno,dname

Now everything is ok:

CaptureMV009

I can use the ‘get recommendation’ to see that there’s nothing else to do:

CaptureMV010

Here is the SQL generated:

CREATE MATERIALIZED VIEW "SCOTT"."MV_EMP_DEPT" USING INDEX REFRESH FORCE ON DEMAND ENABLE QUERY REWRITE AS
select deptno,dname,count(*),sum(sal),count(sal)
from scott.dept join scott.emp using (deptno)
group by deptno,dname
BEGIN DBMS_STATS.GATHER_TABLE_STATS(ownname =>'SCOTT', tabname => 'MV_EMP_DEPT'); END;

dbms_mview

If you don’t have Enterprise Manager, you can do the same manually.

First create the table to store the result:

$ ( cd $ORACLE_HOME/rdbms/admin ; ls *xmv*sql; )
utlxmv.sql
(yes I don’t have to remember the name, I just remember ‘xmv’ for explain mview and ‘xrw’ for explain rewrite)
$ sqlplus scott/tiger @ ?/rdbms/admin/utlxmv.sql

SQL*Plus: Release 11.2.0.3.0 Production on Thu Dec 17 15:09:36 2015
Copyright (c) 1982, 2011, Oracle.  All rights reserved.

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

Table created.

SQL> l
  1  CREATE TABLE MV_CAPABILITIES_TABLE
...

And here is the result after running
exec dbms_mview.explain_mview('SCOTT.MV_EMP_DEPT');
select * from scott.MV_CAPABILITIES_TABLE;
on SQL Developer CaptureMV013

That was about refresh. The rewrite capabilities can be explained in a similar way, but that was in a previous blog post.