How to refresh materialized views faster in 19c?

When I finished upgrading a database from Oracle 11.2 to Oracle 19.24, my customer noticed delays in the fast refresh processes of materialized views: what once took less than 30 minutes now takes hours and hours!

I verified that the statistics were up to date, that the materialized view logs were not too big, and that everything was indexed, but the times did not improve.

There was already talk about downgrading to Oracle 11.2, but happily, I was able to remedy the problem, and with just one command!

Wanna know what it is? Then continue reading—it could save your life if you ever find yourself in a situation like this.

The problem

While reviewing the code for the application that refreshes the approximately 400 materialized views, I discovered that a hidden parameter had been changed for some of them.

DECLARE
  . . .
BEGIN
  EXECUTE IMMEDIATE
    'alter session set "_mv_refresh_use_stats"=FALSE';
  . . .
  DBMS_MVIEW.REFRESH ( 'INS00.MV_POLICY', 'F' );
  . . .
END;

I addressed the programmers about the reasoning behind setting _mv_refresh_use_stats=false, but the roots have been lost.

I search My Oracle Support and see multiple notes advising that change, with the goal of boosting fast refresh performance:

420040.1Materialized View Fast Refresh Is Slow Due to a Poor Execution Plan During the Insert Phase With Hints Such As CARDINALITY, NO_SEMI_JOIN, and HASH_SJ
981948.1MSRFWOR module: refresh collection snapshots runs longer than 3 hours
145419.1How to Setup and Run Data Collections
1067892.1Performance issue - refresh collections snapshot when run for all
1063953.1Refresh Collection Snapshots Performance - Managing MLOG$ Tables and Snapshots for Data Collections

The enigma has been solved: when they created the application for refreshing materialized views, they ran into performance issues, which they fixed by setting the hidden parameter.

However, this was true a decade ago, when they used Oracle 11.2. Will that still be true now that the Oracle 19.24 upgrade is complete?

The solution

While checking the SQL that Oracle creates automatically for fast refreshing materialized views, I found that the HASH_SJ hint is used frequently, as shown in line 11 below.

INSERT  /*+ NOAPPEND */ INTO "INS00"."MV_POLICY" 
SELECT /*+ NO_MERGE("JV$")*/ 
       "MAS$4"."ID","MAS$4"."INITDATE","MAS$4"."ENDDATE",
       "MAS$4"."POLICYNUM","MAS$4"."PREMIUM","MAS$4"."IDAGENT",
       "MAS$2"."IDMOV","MAS$2"."AVISOCOBRANZA",
       "MAS$0"."FIRSTNAME","MAS$0"."LASTNAME"
       "MAS$4".ROWID,"MAS$1".ROWID,"MAS$2".ROWID, "JV$"."RID$","MAS$0".ROWID 
  FROM ( SELECT "MAS$"."ROWID" "RID$",
                "MAS$".* 
           FROM "INS00"."MV_POLICY_LAST_MOV" "MAS$" W 
           HERE ROWID IN (SELECT /*+ HASH_SJ */  
                                 CHARTOROWID("MAS$"."M_ROW$$") RID$     
                            FROM "INS00"."MLOG$_VM_POLICY_LAST_MOV" "MAS$"   
                           WHERE "MAS$".SNAPTIME$$ > :B_ST3 
                         )
       )  AS OF SNAPSHOT(:B_SCN) "JV$", 
       "INS00"."CUSTOMER" AS OF SNAPSHOT(:B_SCN)  "MAS$0", 
       "INS00"."AGENT" AS OF SNAPSHOT(: B_SCN)  "MAS$1", 
       "INS00"."POLICY_MOV" AS OF SNAPSHOT(:B_SCN)  "MAS$2", 
       "INS00"."POLICY" AS OF SNAPSHOT(:B_SCN) "MAS$4" 
 WHERE "MAS$4"."ID"="JV$"."ID" 
   AND "MAS$2"."IDMOV"="JV$"."MOV" 
   AND "MAS$2"."ID"="JV$"."ID" 
   AND "MAS$4"."IDAGENTE"="MAS$1" ."IDAGENT"(+) 
   AND "MAS$4"."IDCUSTOMER"="MAS$0"."IDCUSTOMER"(+)

My Oracle Support has multiple notes showing that the use of the HASH_SJ hint has been connected with performance issues with fast refreshing materialized views.

1388637.1How To Troubleshoot Materialized View Fast Log Timestamp-based Refresh Performance Issues
733054.1Fast Refresh of Mview Taking 20 Min. Due to Hints & Full Table Scans of 20gb Table
2862145.1Refresh Collection Snapshot Is Taking Very Long To Complete - Performance Issue with Large Base Table Row Count

Note 2862145.1 is the most explicit in highlighting the issue and its solution:

The RDBMS Optimizer chooses how the Snapshots are refreshed during Refresh Collection Snapshots.

In RDBMS 19c version - it was found that Optimizer was choosing to use the hint /*+ HASH_SJ */ - which is a known performance issue.

In the past, we have recommended setting DB parameter _mv_refresh_use_stats - false and this was correct setting for earlier DB versions.

On 19c, we need to set this parameter - true to avoid DB Optimizer choosing to use /*+ HASH_SJ */ to refresh the snapshot.

Bingo! What was advised in Oracle 11.2 is no longer recommended in 19.24, therefore we make the adjustment at the instance level and wait to see what happens with the queries.

SQL> ALTER SYSTEM SET "_mv_refresh_use_stats"=TRUE SCOPE=BOTH SID='*';
As shown below, in line 11, the HASH_SJ hint is no longer used, confirming that the change has taken effect.
INSERT  /*+ NOAPPEND */ INTO "INS00"."MV_POLICY" 
SELECT /*+ NO_MERGE("JV$") */ 
       "MAS$4"."ID","MAS$4"."INITDATE","MAS$4"."ENDDATE",
       "MAS$4"."POLICYNUM","MAS$4"."PREMIUM","MAS$4"."IDAGENT",
       "MAS$2"."IDMOV","MAS$2"."AVISOCOBRANZA",
       "MAS$0"."FIRSTNAME","MAS$0"."LASTNAME"
       "MAS$4".ROWID,"MAS$1".ROWID,"MAS$2".ROWID, "JV$"."RID$","MAS$0".ROWID 
  FROM ( SELECT "MAS$"."ROWID" "RID$",
                "MAS$".* 
           FROM "INS00"."MV_POLICY_LAST_MOV" "MAS$" 
          WHERE ROWID IN (SELECT /*+ CARDINALITY(MAS$ 294) NO_SEMIJOIN */  
                                 CHARTOROWID("M AS$"."M_ROW$$") RID$     
                            FROM "INS00"." MLOG$_VM_POLICY_LAST_MOV" "MAS$"   
                           WHERE "MAS$".SNAPTIME$$ > :B_ST3 
                         )
       )  AS OF SNAPSHOT(:B_SCN) "JV$", 
       "INS00"."CUSTOMER" AS OF SNAPSHOT(:B_SCN)  "MAS$0", 
       "INS00"."AGENT" AS OF SNAPSHOT(:B_SCN)  "MAS$1", 
       "INS00"."POLICY_MOV" AS OF S NAPSHOT(:B_SCN)  "MAS$2", 
       "INS00"."POLICY" AS OF SNAPSHOT(:B_SCN)  "MAS$4" 
 WHERE "MAS$4"."ID"="JV$"."ID" 
   AND "MAS$2"."IDMOV"="JV$"."MOV" 
   AND "MAS$2"."ID"="JV$"."ID" 
   AND "MAS$4"."CODSISTEMA"="MAS$1"."CODSISORI"(+) 
   AND "MAS$4"."IDAGENTE"="MAS$1" ."IDAGENT"(+) 
   AND "MAS$4"."IDCUSTOMER"="MAS$0"."IDCUSTOMER"(+)

After several days of applying the parameter change, execution times improved, and the application can now refresh all materialized views in less than 30 minutes, thus we can consider the problem solved.

Based on this experience, if you have Oracle 19c databases that rely on materialized views, don’t be afraid to set _mv_refresh_use_stats=true. You are welcome to thank me later

Recent Posts

out-of-place patching - patch new OH
Second post of a series dedicated to the art of Oracle patching. We continue with out-of-place patching, the recommended and also the most efficient way.
in-place patching - apply patch OH
First post of a series dedicated to the art of Oracle patching. We start with in-place patching, the most common and also the most dangerous way.
Learn how to download Oracle patches, both manually and automated, using the getMOSPatch utility.
Oracle Support Timeline
Oracle has decided to extend the Premier Support for 2 more years, so it will no longer expire in 2024 but in 2026!
Link to article published in Toad World, on how to apply an out-of-place patch to Grid Infrastructure, using a Golden Image.
Link to article published in Toad World, on how to apply an out-of-place patch to Grid Infrastructure, in rolling mode.

Need Help?

Fill in these details and I will be in touch as soon as possible.