In my present db implementation, my db does not has any data/table. All the data it gets is from other sources using dblinks and then populate Materialized Views. These MVs in actual being used by my db to serve customer requests. To implement these MVs we have created simple views like this,
CREATE View vw_Get_Data
AS
SELECT
FROM Table1@sourceDbLink t1
LEFT OUTER JOIN Table2@sourceDbLink t2 ON t1.id = t2.id
LEFT OUTER JOIN Table3@sourceDbLink t3 ON t2.id = t3.id
LEFT OUTER JOIN Table4@sourceDbLink t4 ON t3.id = t4.id
LEFT OUTER JOIN Table5@sourceDbLink t5 ON t4.id = t5.id
LEFT OUTER JOIN vw_Other_Source1 vw1 ON t1.id = vw1.id
LEFT OUTER JOIN vw_Other_Source2 vw2 ON vw1.id = vw2.id
Now we are using this view to populate materialized view and below is the code for the same,
CREATE MATERIALIZED VIEW schema.mv_Get_Data
BUILD IMMEDIATE
REFRESH COMPLETE ON DEMAND
DISABLE QUERY REWRITE
AS
SELECT * FROM vw_Get_Data;
This MV is scheduled to be refreshed once every 24 hours and takes approx. 20 mins to get refreshed completely.
Now we have been asked to increase the refresh frequency and to do so we are thinking to implementing MV with FAST refresh. To do so we have implemented MV Log tables in the source db tables and created MVs with fast refresh for each table to create exact replica locally in my DB. Since we have 5 source table and hence created 5 MV log table at source db and also 5 corresponding MVs with Fast refresh option. And then implemented a simple view on top of these Fast refreshed MVs and then populated the final MV which is being used by application. Thanks to Connor McDonald with his suggestions I was able to create MV with Fast refresh. Below is the code of the new implementation.
Sample of one MV with FAST refresh to create replica of source table in my local db. Materialized View Logs are already been created in source table (Table1)
CREATE MATERIALIZED VIEW MV1
BUILD IMMEDIATE
REFRESH FAST ON DEMAND
WITH PRIMARY KEY
AS
SELECT * FROM Table1@sourceDbLink;
Code sample of new simple view with joins of all Fast refreshed MVs,
CREATE View vw_New_Get_Data
AS
SELECT
FROM Table1@sourceDb t1
LEFT OUTER JOIN MV1 t2 ON t1.id = t2.id
LEFT OUTER JOIN MV2 t3 ON t2.id = t3.id
LEFT OUTER JOIN MV3 t4 ON t3.id = t4.id
LEFT OUTER JOIN MV4 ON t4.id = t5.id
LEFT OUTER JOIN vw_Local vw1 ON t1.id = vw1.id
LEFT OUTER JOIN vw_Source2 vw2 ON vw1.id = vw2.id;
Please find below the code of new final MV which we are planning to be exposed to calling applications,
CREATE MATERIALIZED VIEW schema.New_mv_Get_Data
BUILD IMMEDIATE
REFRESH COMPLETE ON DEMAND
DISABLE QUERY REWRITE
AS
SELECT * FROM vw_New_Get_Data;
Then created scheduled job to executed this MV on demand. My main concern here is PERFORMANCE. i.e. In our previous implementation also we were joining data from all the sources in a simple view and then populated final MV using that simple view.
Also in our new implementation we are running MV with Fast refresh only to replicate the source table locally, later we are again joining these Fast refreshed MVs in simple view which is then used to populate final MV.
My main concern here is Performance because in my initial test i have not got any significant performance improvement i.e. in term of refresh time. Also we have tried with Indexes but not find satisfactory results. Since joins are impacting the performance and the final MV is being refreshed COMPLETE and all the time it is joining the Fast refreshed MVs (which are local to the db). Each source table/MVs are of 3 Million records.
Request you to please suggest if there is any better way we can improve the performance of this new requirement as business is asking this to get refreshed in every 45 mins instead of once in 24 hours and only a single refresh takes 20 mins. Also during the time of refresh if applications requests for any data from these MVs, then no data will be returned to the calling application.
The aim here will be to get FAST refresh mviews all the way along the chain. You can have mview logs on mviews, and mviews of mviews can be fast refreshable. Here's an example of that:
SQL> drop materialized view mv1 ;
Materialized view dropped.
SQL> drop materialized view mv2 ;
Materialized view dropped.
SQL> drop table t purge;
Table dropped.
SQL>
SQL> create table t as select * from dba_objects
2 where object_id is not null;
Table created.
SQL>
SQL> alter table t add primary key (object_id);
Table altered.
SQL>
SQL> create materialized view log on t with rowid (owner) including new values;
Materialized view log created.
SQL>
SQL> create materialized view mv1
2 build immediate
3 refresh fast on demand
4 as
5 select owner, count(*) cnt from t group by owner;
Materialized view created.
SQL>
SQL> create index mv1_ix on mv1 ( owner );
Index created.
SQL>
SQL> alter materialized view mv1 add unique ( owner );
Materialized view altered.
SQL>
SQL> create materialized view log on mv1 with rowid (owner, cnt) including new values;
Materialized view log created.
SQL>
SQL>
SQL> create materialized view mv2
2 build immediate
3 refresh fast on demand
4 as
5 select substr(owner,1,1) prefix, count(*) c from mv1 group by substr(owner,1,1);
Materialized view created.
SQL>
SQL>
SQL> select * from mv1 where owner like 'A%' order by 1;
OWNER CNT
------------------------------ ----------
APEX_040200 3417
APEX_050000 3601
APEX_LISTENER 22
APPQOSSYS 5
ASKTOM 202
AUDSYS 12
6 rows selected.
SQL> select * from mv2 where prefix like 'A%' order by 1;
P C
- ----------
A 6
1 row selected.
SQL>
SQL> delete from t where owner like 'ASK%';
202 rows deleted.
SQL> commit;
Commit complete.
SQL>
SQL> select count(*) from MLOG$_T;
COUNT(*)
----------
202
1 row selected.
SQL>
SQL> exec dbms_mview.refresh('MV1','F');
PL/SQL procedure successfully completed.
SQL>
SQL> select * from mv1 where owner like 'A%' order by 1;
OWNER CNT
------------------------------ ----------
APEX_040200 3417
APEX_050000 3601
APEX_LISTENER 22
APPQOSSYS 5
AUDSYS 12
5 rows selected.
SQL>
SQL> select count(*) from MLOG$_MV1;
COUNT(*)
----------
3
1 row selected.
SQL>
SQL> exec dbms_mview.refresh('MV2','F');
PL/SQL procedure successfully completed.
SQL>
SQL> select * from mv2 where prefix like 'A%' order by 1;
P C
- ----------
A 5
1 row selected.
SQL>
SQL>