27 October, 2019

Basic Replication -- 9 : BUILD DEFERRED

A Materialized View can be created with all the target rows pre-inserted (and subsequently refreshed for changes).  This is the default behaviour.

However, it is possible to define a Materialized View without actually populating it.

You might want to take such a course of action for scenarios like :

1.  Building a number of Materialized Views along with a code migration but not wanting to spend time that would be required to actually populate the MVs  and deferring the population to a subsequent maintenance window after which the code and data will be referenced by the application/users

2.  Building a number of MVs in a Tablespace that is initially small but will be enlarged in the maintenance window to handle the millions of rows that will be inserted

3.  Building an MV definition without actually having all the "clean" Source Table(s) rows currently available, deferring the cleansing of data to a later date and then populating the MV after the cleansing

The BUILD DEFERRED clause comes in handy here.

Let's say that we have a NEW_SOURCE_TABLE (with many rows and/or with rows that are yet to be cleansed) and want to build an "empty" MV on it  (OR that this MV is one of a number of MVs that are being built together simply for migration of dependent code, without the data).

SQL> desc new_source_table
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL NUMBER
 DATA_ELEMENT_1                                     VARCHAR2(15)
 DATA_ELEMENT_2                                     VARCHAR2(15)
 DATE_COL                                           DATE

SQL> create materialized view log on new_source_table;
create materialized view log on new_source_table
ERROR at line 1:
ORA-12014: table 'NEW_SOURCE_TABLE' does not contain a primary key constraint

SQL> create materialized view log on new_source_table with rowid;

Materialized view log created.

SQL> create materialized view new_mv
  2  build deferred
  3  refresh with rowid
  4  as select id as id_number,
  5  data_element_1 as data_key,
  6  data_element_2 as data_val,
  7  date_col as data_date
  8  from new_source_table
  9  /

Materialized view created.


Notice that my Source Table currently does not have a Primary Key.  The MV Log can be created with the "WITH ROWID" clause in the absence of the Primary Key.
The Materialized View is also built with the ROWID as the Refresh cannot use a Primary Key.
Of course, you may well have a Source Table with a Primary Key.  In that case, you can continue to default using the Primary Key instead of the ROWID

Once the Source Table is properly populated / cleansed and/or the tablespace containing the MV is large enough, the MV is first refreshed with a COMPLETE Refresh and subsequently with FAST Refresh's.

SQL> select count(*) from new_source_table;


SQL> execute dbms_mview.refresh('NEW_MV','C',atomic_refresh=>FALSE);

PL/SQL procedure successfully completed.


Subsequently, when one or more rows are inserted/updated in the Source Table, the next Refresh is a Fast Refresh.

SQL> execute dbms_mview.refresh('NEW_MV','F');

PL/SQL procedure successfully completed.

SQL> select mview_name, refresh_mode, refresh_method, last_refresh_type
  2  from user_mviews
  3  where mview_name = 'NEW_MV'
  4  /

------------------ --------- -------- --------
NEW_MV             DEMAND    FORCE    FAST


Thus, we started off with an empty MV and later used REFRESHs (COMPLETE and FAST) to populate it.

No comments: