oracledba.help
Schema

Materialized Views

Overview

A Materialized View (MV) contains the results of a query and is physically stored in a database object that resembles a table. A MV can have better performance than selecting the same data-set each time you need it.

MV Creation Fun Facts!

  • Ensure your TEMP & destination tablespace are large enough.
    Otherwise you might see: ORA-01652: unable to extend temp segment by 8192 in tablespace MY_TS
  • Ensure the user creating the MV has the required privs:
    • ALTER USER scott QUOTA UNLIMITED on HR_TS;
    • GRANT SELECT on hr.employee to scott;
    • GRANT CREATE MATERIALIZED VIEW TO scott;
      The user whose schema contains the MV must have sufficient quota in the destination tablespace to store the master table and index of the MV or must have the UNLIMITED TABLESPACE system privilege.
  • The MV can be created from any schema where you have the adequate privs.
  • If you need an MV Log, it must be created by the owner of the table.
  • For MV Refreshes, ensure your UNDO tablepace is large enough.
    Optionally use: atomic_refresh=>false
  • Creating a MV using the PARALLEL option decreases the creation time and also tends to use much less TEMP tablespace.
  • The PARALLEL value used on creation will also be used when the MV is accessed and refreshed.
  • Do not use "double-quotes" for any column names in your SQL or you will get invalid identifier errors when referring to the column using your MV.
  • When a MV is created if any of the tables referenced in its definition are changed (via DML or DDL operation) it will cause it to show as INVALID in the dba_objects. This is expected behavior. The MV will still work as normal. See 264036.1.
  • Using "double-quotes" requires you to refer to that column using the EXACT syntax used on creation limiting your MV's usefulness.

Create

CREATE MATERIALIZED VIEW <MV_Name_Here>
  [BUILD IMMEDIATE|DEFERRED]
  [LOGGING|NOLOGGING]
  [ON DEMAND|ON COMMIT]
  [ON PREBUILT TABLE]
  [PARALLEL n]
  [QUERY REWRITE]
  [REFRESH FAST|COMPLETE|FORCE]
  [TABLESPACE ts_name]
AS <SELECT_SQL_Here>;
 -- Connect to Schema to Create\Own MV
 connect scott/********@MYDB

 -- Confirm Have Access to Table(s) for MV
 SELECT count(*) FROM hr.acctcommon;

 -- Create MV
 CREATE MATERIALIZED VIEW mv_acctcommon
   TABLESPACE hr
   NOLOGGING 
   NOCACHE 
   PARALLEL 8 
   BUILD IMMEDIATE 
   REFRESH FORCE ON DEMAND
 AS 
  SELECT 
     AC.ACCTNBR AcctNbr, 
     AC.TAXRPTFORPERSNBR PersNbr, 
     AC.TAXRPTFORORGNBR OrgNbr, 
     AC.OWNERNAME OwnerName 
  FROM HR.ACCTCOMMON AC 
  ORDER BY AcctNbr; 

 -- Assign Privs to MV As Needed
 GRANT select ON scott.mv_acctcommon TO jsmith;
  • The above is common for MV that is refreshed manually and does not require an MV Log.
  • The order of options can be picky. Above order works.

Display

SELECT * FROM all_registered_mviews;
SELECT * FROM all_refresh;
SELECT * FROM all_refresh_children;
SELECT * FROM v$mvrefresh;

COL owner          FORMAT a15
COL name           FORMAT a20
COL mview_site     FORMAT a15
COL can_use_log    FORMAT a3  HEAD 'Log'
COL updatable      FORMAT a3  HEAD 'Upd'
COL refresh_method FORMAT a14
COL mview_id       FORMAT 999999
SELECT mview_site,owner,name,can_use_log,updatable,refresh_method,mview_id, version 
FROM all_registered_mviews
ORDER BY owner,name;

SELECT owner,name,QUERY_TXT
FROM all_registered_mviews
ORDER BY owner,name;

Drop

DROP MATERIALIZED VIEW [schema.]<MVName>;
DROP MATERIALIZED VIEW scott.mv_acctcommon;

All data in the mv table is automatically deleted as part of the dropping process. All indexes and keys for the MV are dropped as well.

Optimize

 ALTER TABLE scott.MyMV ENABLE ROW MOVEMENT;
 ALTER TABLE scott.MyMV SHRINK SPACE COMPACT;
 ALTER TABLE scott.MyMV SHRINK SPACE;
 EXEC DBMS_STATS.gather_table_stats(ownname =>'SCOTT', 
                                    tabname => 'MyMV', 
                                    method_opt => 'FOR ALL COLUMNS SIZE AUTO', 
                                    estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE);
 SELECT count(*) FROM MySchema.MyMV;

You generally want to do this after creating or refreshing a MV.

Manual Refresh

EXECUTE DBMS_MVIEWS.refresh('[schema.]<MVName>','<Type>'[,'atomic_refresh=>true|false']);
EXEC dbms_mview.refresh('scott.mv_acctcommon', method=>'C', atomic_refresh=>false);
  • Using PARALLEL has no effect on refresh. It will use the PARALLEL value set when you created the MV.
  • With atomic_refresh=false logs\undo will not be generated and thus faster too.
  • Legacy method: EXECUTE DBMS_SNAPSHOT.REFRESH('scott.mv_acctcommon','C');

Common Issues

ORA-04021: timeout occurred while waiting to lock object

Solution

 -- Method 1
 1. Look at the DDL for the MVIEW and identify the tables it depends on.

 2. Determine if there is any long running DML occurring on any of the tables 
    the MVIEW depends on.

 3. Retry the drop of the MVIEW when you know there is no long running DML 
    happening on the any of the tables the MVIEW depends on.

 -- Method 2
 1. Use v$access to see if anyone is using the MV (object)?

    SELECT owner, object FROM v$access 
    WHERE owner NOT IN('DBSNMP','GSMADMIN_INTERNAL','PUBLIC','SYS','XDB') 
    ORDER BY owner;

    SELECT object FROM v$access WHERE owner ='ETL';

  2. If there are see if they are using summaries.
     SELECT owner,SUMMARY_NAME FROM dba_summaries;

  3. DROP the corresponding summary(s).
     DROP summary ETL.MV_MYVIEW;
  4. Try now to DROP your MV.
     DROP MATERIALIZED VIEW ETL.MV_MYVIEW;

The above can happen when you DROP MATERIALIZED VIEW MyView.;

<- Schema