Skip to Main Content

SQL & PL/SQL

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

The refresh of a materialized view is becoming progressively slower

BufossMay 12 2024 — edited May 12 2024

Hi all,
I am responsible for an application monitoring of message transfers.
So, my most important table is a table called MSG_EXC_REC which contains records of all messages transferred between countries.
Here is the structure of this table:

CREATE TABLE MSG_EXC_REC
(
   CCN_UNIQUE_ID     VARCHAR2(250) NOT NULL,
   MSG_ID            VARCHAR2(48) NOT NULL,
   MSG_TYPE          VARCHAR2(32) NOT NULL,
   MSG_SIZE          NUMBER(15),
   SENDER            VARCHAR2(2)  NOT NULL,
   RECIPIENT         VARCHAR2(2)  NOT NULL,
   CORREL_ID         VARCHAR2(48),
   DOMAIN            VARCHAR2(20) NOT NULL, 
   MODIFICATION_DATE TIMESTAMP    NOT NULL,
   M_MIN_DATE        TIMESTAMP    NOT NULL,
   M_MAX_DATE        TIMESTAMP    NOT NULL,
   MSG_SEND_DATE     TIMESTAMP,
   MSG_REC_DATE      TIMESTAMP,
   PRIMARY KEY (CCN_UNIQUE_ID)
)
PARTITION BY RANGE (M_MIN_DATE)
INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'))
(PARTITION BEFORE_2010 VALUES LESS THAN (TO_DATE('01-01-2010', 'DD-MM-YYYY')))
ENABLE ROW MOVEMENT INITRANS 5;

To correlate the sender and receiver of messages, we employ the approach that the correl_id of the received message is the msg_id of a sent message.

At times, there are failures in sending or receiving messages. When the message type (msg_type) contains 906, 907 or 917, it indicates an error occurrence. These error messages are also stored in a table named ERROR_MESSAGE. The connection between the ERROR_MESSAGE table and MSG_EXC_REC relies on the MSG_ID, DOMAIN and MSG_TYPE fields.

CREATE TABLE "ERROR_MESSAGE" (    
   "ID"             NUMBER(12,0) NOT NULL, 
    "CORREL_ID"      VARCHAR2(48 BYTE), 
    "MSG_ID"         VARCHAR2(48 BYTE) NOT NULL, 
    "MSG_REC_DATE"   TIMESTAMP (6) NOT NULL, 
    "MSG_TYPE"       VARCHAR2(32 BYTE) NOT NULL, 
    "SYNC_ID"        NUMBER(12,0), 
    "DOMAIN"         VARCHAR2(20 BYTE) NOT NULL, 
    "MSG_SIZE"       NUMBER(10,0), 
    "XML_CONTENT"    CLOB, 
     PRIMARY KEY ("ID")
);

We utilize 3 additional tables, namely ERROR_MESSAGE_906, ERROR_MESSAGE_907, and ERROR_MESSAGE_917, to gather specific information about errors based on the msg_type field. Below are the definitions for each of these tables:

CREATE TABLE "ERROR_MESSAGE_906" (    
   "ID"             NUMBER(12,0) NOT NULL, 
    "ERROR_TYPE"     VARCHAR2(2 BYTE) NOT NULL, 
    "ORIGINAL_VALUE" VARCHAR2(140 BYTE), 
    "POINTER"        VARCHAR2(210 BYTE), 
    "REASON"         VARCHAR2(6 BYTE), 
    "EM_ID"          NUMBER(12,0) NOT NULL, 
    PRIMARY KEY ("ID"), 
    CONSTRAINT "ERRORMESSAGE906EMID" FOREIGN KEY ("EM_ID")
    REFERENCES "ERROR_MESSAGE" ("ID")
);

CREATE TABLE "ERROR_MESSAGE_907" (    
   "ID"             NUMBER(12,0) NOT NULL, 
    "ACTREC_IN"      VARCHAR2(3 BYTE), 
    "ERROR_CODE_IN"  VARCHAR2(2 BYTE), 
    "MSG_TYPE"       VARCHAR2(6 BYTE), 
    "ACTREC_MSG"     VARCHAR2(3 BYTE), 
    "ERROR_CODE_MSG" VARCHAR2(2 BYTE), 
    "EM_ID"          NUMBER(12,0) NOT NULL, 
     PRIMARY KEY ("ID"), 
     CONSTRAINT "ERRORMESSAGE907EMID" FOREIGN KEY ("EM_ID")
      REFERENCES "ERROR_MESSAGE" ("ID")
);

CREATE TABLE "ERROR_MESSAGE_917" (    
   "ID"             NUMBER(12,0) NOT NULL, 
    "LOCATION"       VARCHAR2(350 BYTE), 
    "LINE"           VARCHAR2(9 BYTE), 
    "COLUMN_NUM"     VARCHAR2(9 BYTE), 
    "REASON"         VARCHAR2(350 BYTE), 
    "ORIGINAL_VALUE" VARCHAR2(350 BYTE), 
    "ERROR_CODE"     VARCHAR2(2 BYTE), 
    "EM_ID"          NUMBER(12,0) NOT NULL, 
     PRIMARY KEY ("ID"), 
     CONSTRAINT "ERRORMESSAGE917EMID" FOREIGN KEY ("EM_ID")
      REFERENCES "ERROR_MESSAGE" ("ID") 
);

In the initial stages of the system, we operated under the assumption that the msg_id was unique for every message. However, it seems that this may have been altered last year.
I encountered an issue with a materialized view we utilize. This materialized view is tasked with retrieving all error_messages, joining them with msg_exc_rec, and, if applicable, joining them again with msg_exc_rec to get some info for the original message. (We have also implemented some date limitations to enhance performance.)

CREATE MATERIALIZED VIEW "MV_ERROR_MESSAGES"
REFRESH COMPLETE ON DEMAND
AS SELECT TMPUNION.ID AS EM_ID
     , replace(TMPUNION.DOMAIN, 'AES', 'ECS') AS DOMAIN
     , TMPUNION.PHASE
     , SUBSTR(TMPUNION.MSG_TYPE, 0, 6) AS MSG_TYPE
     , TMPUNION.SIZE_CATEGORY
     , TMPUNION.IS_ZIP
     , TMPUNION.MSG_REC_DATE
     , SUBSTR(TMPUNION.SEND_C_CODE, -least(length(TMPUNION.SEND_C_CODE), 2)) AS SEND_C_CODE
     , SUBSTR(TMPUNION.REC_C_CODE, -least(length(TMPUNION.REC_C_CODE), 2)) AS REC_C_CODE
     , MSG.CCN_UNIQUE_ID
     , TMPUNION.ERROR_TYPE
     , TMPUNION.ERROR_REASON
     , TMPUNION.ERROR_POINTER
     , MSG.ENV
     , MSG.REJECTED_MESSAGE_TYPE
     , MSG.REJECTED_MESSAGE_SENDER
     , MSG.REJECTED_MESSAGE_RECIPIENT
     , MSG.REJECTED_ID
     , CASE
         WHEN TMPUNION.MSG_TYPE LIKE 'CD9%' AND MSG.RECIPIENT_GW IN ('XXIP1','XXIP2','XXIP4','XXIP5','XXIP7','XXIP9','XXIB1','XXIB2','XXIB5','XXIB7') THEN 'EX'
         WHEN TMPUNION.ERROR_REASON LIKE 'NCAv%' THEN 'EX'
         WHEN TMPUNION.MSG_TYPE LIKE 'CD917%' AND MSG.SENDER_GW IN ('XXIP1','XXIP2','XXIP4','XXIP5','XXIP7','XXIP9','XXIB1','XXIB2','XXIB5','XXIB7') THEN 'ET' --Endogen ToBe
         WHEN TMPUNION.ERROR_REASON = 'ieCAvB' THEN 'ET'
         WHEN TMPUNION.MSG_TYPE LIKE 'CD907%' AND MSG.SENDER_GW IN ('XXIP1','XXIP2','XXIP4','XXIP5','XXIP7','XXIP9','XXIB1','XXIB2','XXIB5','XXIB7') THEN 'EL' --Endogen Legacy
         WHEN TMPUNION.ERROR_REASON = 'ieCAvC' THEN 'EL'
              ELSE 'IF' --No conversion
END AS IECA_STATUS
     , TMPUNION.ERROR_ID AS ERROR_ID
     , MSG.IS_IECA
FROM
(
SELECT MDI.ID, MDI.DOMAIN, MDI.PHASE, MDI.MSG_TYPE, MDI.SIZE_CATEGORY, MDI.IS_ZIP, MDI.MSG_REC_DATE, MDI.SEND_C_CODE, MDI.REC_C_CODE, MDI.MSG_ID, MD906.ERROR_TYPE AS ERROR_TYPE, MD906.REASON AS ERROR_REASON, MD906.POINTER AS ERROR_POINTER, MD906.ID AS ERROR_ID
  FROM ERROR_MESSAGE MDI
       INNER JOIN ERROR_MESSAGE_906 MD906 ON MDI.ID = MD906.EM_ID
UNION ALL
SELECT MDI.ID, MDI.DOMAIN, MDI.PHASE, MDI.MSG_TYPE, MDI.SIZE_CATEGORY, MDI.IS_ZIP, MDI.MSG_REC_DATE, MDI.SEND_C_CODE, MDI.REC_C_CODE, MDI.MSG_ID, MD907.ERROR_CODE_IN AS ERROR_TYPE, NULL AS ERROR_REASON, NULL AS ERROR_POINTER, MD907.ID AS ERROR_ID
  FROM ERROR_MESSAGE MDI
       INNER JOIN ERROR_MESSAGE_907 MD907 ON MDI.ID = MD907.EM_ID
UNION ALL
SELECT MDI.ID, MDI.DOMAIN, MDI.PHASE, MDI.MSG_TYPE,MDI.SIZE_CATEGORY, MDI.IS_ZIP, MDI.MSG_REC_DATE, MDI.SEND_C_CODE, MDI.REC_C_CODE, MDI.MSG_ID, MD917.ERROR_CODE AS ERROR_TYPE, MD917.REASON AS ERROR_REASON, NULL AS ERROR_POINTER, MD917.ID AS ERROR_ID
  FROM ERROR_MESSAGE MDI
       INNER JOIN ERROR_MESSAGE_917 MD917 ON MDI.ID = MD917.EM_ID
) TMPUNION
cross apply (
    select CCN_UNIQUE_ID, ENV, REJECTED_ID, RECIPIENT_GW, SENDER_GW, IS_IECA
         , REJECTED_MESSAGE_TYPE, REJECTED_MESSAGE_SENDER, REJECTED_MESSAGE_RECIPIENT
         , ROW_NUM
    from (
        select MER.CCN_UNIQUE_ID, MER.ENV, MER.CORREL_ID as REJECTED_ID, MER.RECIPIENT_GW, MER.SENDER_GW, MER.IS_IECA
            , SUBSTR(ORIGINAL_MER.MSG_TYPE, 0, 6) AS REJECTED_MESSAGE_TYPE, ORIGINAL_MER.SENDER AS REJECTED_MESSAGE_SENDER
            , ORIGINAL_MER.RECIPIENT AS REJECTED_MESSAGE_RECIPIENT
            , ROW_NUMBER()
              OVER (partition by MER.DOMAIN, MER.ENV, MER.MSG_TYPE, MER.MSG_ID  order by MER.M_MIN_DATE desc) as ROW_NUM
        from MSG_EXC_REC MER
            LEFT JOIN MSG_EXC_REC ORIGINAL_MER ON MER.CORREL_ID = ORIGINAL_MER.MSG_ID
                                              AND MER.DOMAIN = ORIGINAL_MER.DOMAIN
                                              AND MER.M_MIN_DATE >= ORIGINAL_MER.M_MIN_DATE
        where TMPUNION.MSG_ID = MER.MSG_ID
          AND replace(TMPUNION.DOMAIN, 'AES', 'ECS') = MER.DOMAIN
          AND TMPUNION.MSG_TYPE = MER.MSG_TYPE
          AND TMPUNION.MSG_REC_DATE BETWEEN MER.M_MIN_DATE - interval '1' hour
                                        AND MER.M_MIN_DATE + interval '5' hour
          AND MER.M_MIN_DATE BETWEEN MER.M_MIN_DATE - interval '4' year
                                 AND SYSDATE
    )
    where ROW_NUM=1
) MSG;

As you can see I use the ROW_NUM = 1, as I want to join with exactly one message. This added dut to the issue with the multiple msg_ids for different messages.

The materialized view used to refresh in about 2:30 hours. However, recently, it has been taking nearly 7 hours. Upon investigation, I discovered that there are error_messages with the same msg_id. I found one msg_id that appears 100,000 times.

The execution plan is below

Do you have any ideas on how to enhance the definition of this materialized view? Is the cross apply operation I'm using too resource-intensive?
Alternatively, is there a method to exclude msg_ids from error_message that have more than 2000 rows?

Thank you in advance for any advice you can provide. Your input is greatly appreciated.

Comments
Post Details
Added on May 12 2024
1 comment
330 views