SQL优化案例之where exists(col1=xxx or col2=xxx)等价改写

Posted robinson1988

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL优化案例之where exists(col1=xxx or col2=xxx)等价改写相关的知识,希望对你有一定的参考价值。

一位客户EBS中某个请求跑了42分钟,EBS顾问叫我优化一下,查看跑得慢请求的module
发现一条SQL语句要跑42分钟,SQL语句文本如下:

SELECT GCC.SEGMENT1,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 1, GCC.SEGMENT1) SEGMENT1_DESC,
       GCC.SEGMENT3,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 3, GCC.SEGMENT3) SEGMENT3_DESC,
       GCC.SEGMENT2,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 2, GCC.SEGMENT2) SEGMENT2_DESC,
       NBD.BUSSION_CODE,
       NBD.BUSSION_NAME,
       GCC.SEGMENT4,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 4, GCC.SEGMENT4) SEGMENT4_DESC,
       GCC.SEGMENT5,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 5, GCC.SEGMENT5) SEGMENT5_DESC,
       GCC.SEGMENT6,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 6, GCC.SEGMENT6) SEGMENT6_DESC,
       GCC.SEGMENT7,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 7, GCC.SEGMENT7) SEGMENT7_DESC,
       GCC.SEGMENT8,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 8, GCC.SEGMENT8) SEGMENT8_DESC,
       DECODE(GBL.CURRENCY_CODE,
              GLE.CURRENCY_CODE,
              (NVL(GBL.BEGIN_BALANCE_DR_BEQ, 0) -
              NVL(GBL.BEGIN_BALANCE_CR_BEQ, 0) +
              NVL(GBL.PERIOD_NET_DR_BEQ, 0) - NVL(GBL.PERIOD_NET_CR_BEQ, 0)),
              (NVL(GBL.BEGIN_BALANCE_DR, 0) - NVL(GBL.BEGIN_BALANCE_CR, 0) +
              NVL(GBL.PERIOD_NET_DR, 0) - NVL(GBL.PERIOD_NET_CR, 0))) END_AMT,
       DECODE(GBL.CURRENCY_CODE,
              GLE.CURRENCY_CODE,
              (NVL(GBL.BEGIN_BALANCE_DR_BEQ, 0) -
              NVL(GBL.BEGIN_BALANCE_CR_BEQ, 0) +
              NVL(GBL.PERIOD_NET_DR_BEQ, 0) - NVL(GBL.PERIOD_NET_CR_BEQ, 0)),
              (NVL(GBL.BEGIN_BALANCE_DR_BEQ, 0) -
              NVL(GBL.BEGIN_BALANCE_CR_BEQ, 0) +
              NVL(GBL.PERIOD_NET_DR_BEQ, 0) - NVL(GBL.PERIOD_NET_CR_BEQ, 0))) END_AMT_BEQ,
       GBL.CURRENCY_CODE,
       GCC.SEGMENT9,
       GCC.CODE_COMBINATION_ID,
       (SELECT TO_DATE(MAX(FLV.ATTRIBUTE34), 'YYYY/MM/DD HH24:mi:ss') INV_DATE
          FROM FND_FLEX_VALUES_VL FLV
         WHERE FLV.ENABLED_FLAG = 'Y'
           AND (FLV.FLEX_VALUE = GCC.SEGMENT4 OR
               FLV.FLEX_VALUE = GCC.SEGMENT5)
           AND FLV.ATTRIBUTE34 IS NOT NULL) INV_DATE,
       GLE.CURRENCY_CODE CURRENCY_CODE_BEQ,
       NULL NAME,
       '未入账' POST_STATUS,
       'Y' TYPE
  FROM GL_BALANCES          GBL,
       GL_CODE_COMBINATIONS GCC,
       NCM_BU_DEPARTMENT_V  NBD,
       HR_OPERATING_UNITS   HOU,
       GL_LEDGERS           GLE
 WHERE GBL.LEDGER_ID = GLE.LEDGER_ID
   AND GBL.CODE_COMBINATION_ID = GCC.CODE_COMBINATION_ID
   AND GCC.SEGMENT2 = NBD.DEPARTMENT_CODE(+)
   AND GBL.PERIOD_NAME = '2022-09'
   AND GCC.SEGMENT1 = HOU.SHORT_CODE
   AND EXISTS
 (SELECT 1
          FROM NFND_LOOKUP_LINES NLL, NFND_LOOKUP_DETAILS NLD
         WHERE NLD.LINE_CODE = NLL.LINE_CODE
           AND SYSDATE BETWEEN NVL(NLL.START_DATE_ACTIVE, SYSDATE) AND
               NVL(NLL.END_DATE_ACTIVE, SYSDATE)
           AND NVL(NLL.ENABLED_FLAG, 'N') = 'Y'
           AND (GCC.SEGMENT4 = NLD.DETAIL_CODE OR
               GCC.SEGMENT5 = NLD.DETAIL_CODE)
           AND NLL.LOOKUP_TYPE = 'NGL_SUBAC_IC_MAPPING')
   AND NOT EXISTS
 (SELECT 1
          FROM CUST_GENERAL.NGL_INVAILD_SEGMENT_HISTORY T
         WHERE (GCC.SEGMENT4 = T.SEGMENT4_5 OR GCC.SEGMENT5 = T.SEGMENT4_5)
           AND GBL.CURRENCY_CODE = T.CURRENCY_CODE
           AND GCC.SEGMENT1 = T.SEGMENT1)
   AND GCC.SUMMARY_FLAG = 'N'
   AND GLE.LEDGER_CATEGORY_CODE = 'PRIMARY'
   AND GLE.CHART_OF_ACCOUNTS_ID = 50368
   AND XY_COM_DEPT_READ.COM_READ(HOU.ORGANIZATION_ID) = 'Y'
   AND (95 IS NULL OR HOU.ORGANIZATION_ID = 95)
UNION ALL
SELECT GCC.SEGMENT1,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 1, GCC.SEGMENT1) SEGMENT1_DESC,
       GCC.SEGMENT3,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 3, GCC.SEGMENT3) SEGMENT3_DESC,
       GCC.SEGMENT2,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 2, GCC.SEGMENT2) SEGMENT2_DESC,
       NBD.BUSSION_CODE,
       NBD.BUSSION_NAME,
       GCC.SEGMENT4,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 4, GCC.SEGMENT4) SEGMENT4_DESC,
       GCC.SEGMENT5,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 5, GCC.SEGMENT5) SEGMENT5_DESC,
       GCC.SEGMENT6,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 6, GCC.SEGMENT6) SEGMENT6_DESC,
       GCC.SEGMENT7,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 7, GCC.SEGMENT7) SEGMENT7_DESC,
       GCC.SEGMENT8,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 8, GCC.SEGMENT8) SEGMENT8_DESC,
       NIH.END_AMT,
       NIH.END_AMT_BEQ,
       NIH.CURRENCY_CODE,
       GCC.SEGMENT9,
       GCC.CODE_COMBINATION_ID,
       NULL INV_DATE,
       GLE.CURRENCY_CODE CURRENCY_CODE_BEQ,
       GJB.NAME NAME,
       DECODE(GJH.ACCRUAL_REV_STATUS,
              'R',
              '已冲销',
              DECODE(GJH.STATUS,
                     'P',
                     '已过账',
                     'U',
                     '未过账',
                     NULL,
                     '已删除')) POST_STATUS,
       'N' TYPE
  FROM GL_JE_HEADERS GJH,
       GL_JE_BATCHES GJB,
       GL_CODE_COMBINATIONS GCC,
       GL_LEDGERS GLE,
       NCM_BU_DEPARTMENT_V NBD,
       HR_OPERATING_UNITS HOU,
       (SELECT DISTINCT T.JE_HEADER_ID,
                        T.JE_LINE_NUM,
                        T.CODE_COMBINATION_ID,
                        T.POST_GROUP_ID,
                        T.END_AMT,
                        T.END_AMT_BEQ,
                        T.CURRENCY_CODE,
                        T.LEDGER_ID,
                        T.PERIOD_NAME
          FROM CUST_GENERAL.NGL_INVAILD_SEGMENT_HISTORY T) NIH
 WHERE NIH.CODE_COMBINATION_ID = GCC.CODE_COMBINATION_ID
   AND NIH.POST_GROUP_ID = GJB.GROUP_ID
   AND NIH.LEDGER_ID = GLE.LEDGER_ID
   AND GCC.SEGMENT1 = HOU.SHORT_CODE
   AND NIH.JE_HEADER_ID = GJH.JE_HEADER_ID(+)
   AND GCC.SEGMENT2 = NBD.DEPARTMENT_CODE(+)
   AND NIH.PERIOD_NAME = '2022-09'
   AND EXISTS
 (SELECT 1
          FROM NFND_LOOKUP_LINES NLL, NFND_LOOKUP_DETAILS NLD
         WHERE NLD.LINE_CODE = NLL.LINE_CODE
           AND SYSDATE BETWEEN NVL(NLL.START_DATE_ACTIVE, SYSDATE) AND
               NVL(NLL.END_DATE_ACTIVE, SYSDATE)
           AND NVL(NLL.ENABLED_FLAG, 'N') = 'Y'
           AND (GCC.SEGMENT4 = NLD.DETAIL_CODE OR
               GCC.SEGMENT5 = NLD.DETAIL_CODE)
           AND NLL.LOOKUP_TYPE = 'NGL_SUBAC_IC_MAPPING')
   AND XY_COM_DEPT_READ.COM_READ(HOU.ORGANIZATION_ID) = 'Y'
   AND (95 IS NULL OR HOU.ORGANIZATION_ID = 95)
 ORDER BY SEGMENT1, CURRENCY_CODE, INV_DATE;

需要注意的是:做EBS系统SQL的优化,一般都是需要EBS开发配合,因为我们抓到的SQL语句单独运行一般都不会返回结果,需要对SQL进行初始化,比如这条SQL语句在运行之前要先运行:

begin
  fnd_global.apps_initialize(user_id      => 2552,
                             resp_id      => 50729,
                             resp_appl_id => 101);
  mo_global.init('M');
end;
/

上面的初始化语句一般是由EBS开发给到DBA

用瞪眼大法初略看一下,发现问题出在EXISTS子查询中的

 AND (GCC.SEGMENT4 = NLD.DETAIL_CODE OR
               GCC.SEGMENT5 = NLD.DETAIL_CODE)

  AND EXISTS
 (SELECT 1
          FROM NFND_LOOKUP_LINES NLL, NFND_LOOKUP_DETAILS NLD
         WHERE NLD.LINE_CODE = NLL.LINE_CODE
           AND SYSDATE BETWEEN NVL(NLL.START_DATE_ACTIVE, SYSDATE) AND
               NVL(NLL.END_DATE_ACTIVE, SYSDATE)
           AND NVL(NLL.ENABLED_FLAG, 'N') = 'Y'
           AND (GCC.SEGMENT4 = NLD.DETAIL_CODE OR
               GCC.SEGMENT5 = NLD.DETAIL_CODE)
           AND NLL.LOOKUP_TYPE = 'NGL_SUBAC_IC_MAPPING')

跑个SQL MONITOR监控一下

SQL Plan Monitoring Details (Plan Hash Value=2978231168)
=========================================================================================================================================================================================================================
| Id    |                      Operation                       |              Name              |  Rows   | Cost |   Time    | Start  | Execs |   Rows   | Read | Read  |  Mem  | Activity |      Activity Detail       |
|       |                                                      |                                | (Estim) |      | Active(s) | Active |       | (Actual) | Reqs | Bytes |       |   (%)    |        (# samples)         |
=========================================================================================================================================================================================================================
|     0 | SELECT STATEMENT                                     |                                |         |      |           |        |     1 |          |      |       |     . |          |                            |
|     1 |   SORT ORDER BY                                      |                                |       2 | 7289 |           |        |     1 |          |      |       |     . |          |                            |
|     2 |    UNION-ALL                                         |                                |         |      |           |        |     1 |          |      |       |     . |          |                            |
|     3 |     SORT AGGREGATE                                   |                                |       1 |      |           |        |       |          |      |       |     . |          |                            |
|     4 |      NESTED LOOPS                                    |                                |       1 |    7 |           |        |       |          |      |       |     . |          |                            |
|     5 |       INLIST ITERATOR                                |                                |         |      |           |        |       |          |      |       |     . |          |                            |
|     6 |        TABLE ACCESS BY INDEX ROWID BATCHED           | FND_FLEX_VALUES                |       1 |    6 |           |        |       |          |      |       |     . |          |                            |
|     7 |         INDEX RANGE SCAN                             | FND_FLEX_VALUES_01             |       2 |    4 |           |        |       |          |      |       |     . |          |                            |
|     8 |       INDEX UNIQUE SCAN                              | FND_FLEX_VALUES_TL_U1          |       1 |    1 |           |        |       |          |      |       |     . |          |                            |
|     9 |     HASH JOIN OUTER                                  |                                |       1 | 5757 |           |        |     1 |          |      |       | 30720 |          |                            |
|    10 |      JOIN FILTER CREATE                              | :BF0000                        |       1 | 5685 |           |        |     1 |          |      |       |     . |          |                            |
|    11 |       HASH JOIN                                      |                                |       1 | 5685 |         1 |     +6 |     1 |        0 |      |       |   8MB |          |                            |
|    12 |        NESTED LOOPS                                  |                                |       1 | 5685 |         1 |     +6 |     1 |        1 |      |       |     . |          |                            |
|    13 |         NESTED LOOPS                                 |                                |       1 | 5685 |      1633 |     +6 |     1 |        1 |      |       |     . |          |                            |
|    14 |          STATISTICS COLLECTOR                        |                                |         |      |      1635 |     +4 |     1 |    50422 |      |       |     . |          |                            |
|    15 |           NESTED LOOPS                               |                                |       1 | 5684 |      1635 |     +4 |     1 |    50422 |      |       |     . |          |                            |
|    16 |            NESTED LOOPS                              |                                |       8 | 5659 |      1637 |     +2 |     1 |    47093 |      |       |     . |          |                            |
|    17 |             MERGE JOIN CARTESIAN                     |                                |       1 |    5 |         1 |     +2 |     1 |        1 |      |       |     . |          |                            |
|    18 |              NESTED LOOPS                            |                                |       1 |    3 |         1 |     +2 |     1 |        1 |      |       |     . |          |                            |
|    19 |               NESTED LOOPS                           |                                |       1 |    1 |         1 |     +2 |     1 |        1 |      |       |     . |          |                            |
|    20 |                INDEX UNIQUE SCAN                     | HR_ALL_ORGANIZATION_UNTS_TL_PK |       1 |    1 |         1 |     +2 |     1 |        1 |      |       |     . |          |                            |
|    21 |                INDEX UNIQUE SCAN                     | HR_ORGANIZATION_UNITS_PK       |       1 |      |         1 |     +2 |     1 |        1 |      |       |     . |          |                            |
|    22 |               TABLE ACCESS BY INDEX ROWID BATCHED    | HR_ORGANIZATION_INFORMATION    |       1 |    2 |         1 |     +2 |     1 |        1 |      |       |     . |          |                            |
|    23 |                INDEX RANGE SCAN                      | HR_ORGANIZATION_INFORMATIO_FK2 |       1 |    1 |         1 |     +2 |     1 |        1 |      |       |     . |          |                            |
|    24 |              BUFFER SORT                             |                                |       1 |    3 |         1 |     +2 |     1 |        1 |      |       |     . |          |                            |
|    25 |               TABLE ACCESS BY INDEX ROWID BATCHED    | HR_ORGANIZATION_INFORMATION    |       1 |    2 |         1 |     +2 |     1 |        1 |      |       |     . |          |                            |
|    26 |                INDEX RANGE SCAN                      | HR_ORGANIZATION_INFORMATION_N1 |       2 |    1 |         1 |     +2 |     1 |        9 |      |       |     . |          |                            |
|    27 |             TABLE ACCESS BY INDEX ROWID BATCHED      | GL_CODE_COMBINATIONS           |    2379 | 5654 |      2027 |     +4 |     1 |    47093 |      |       |     . |          |                            |
| -> 28 |              INDEX RANGE SCAN                        | GL_CODE_COMBINATIONS_N11       |    4803 |  901 |      2107 |     +2 |     1 |    59161 |   86 | 688KB |     . |          |                            |
|    29 |               NESTED LOOPS                           |                                |       2 |  721 |      2027 |     +4 | 43575 |    30616 |      |       |     . |          |                            |
|    30 |                NESTED LOOPS                          |                                |       2 |  721 |      2027 |     +4 | 43575 |    30616 |      |       |     . |          |                            |
| -> 31 |                 TABLE ACCESS STORAGE FULL FIRST ROWS | NFND_LOOKUP_DETAILS            |       2 |  719 |      2108 |     +1 | 43575 |    30616 |      |       |     . |    99.71 | Cpu (2030)                 |
|    32 |                 INDEX UNIQUE SCAN                    | NFND_LOOKUP_LINES_U1           |       1 |      |      2027 |     +4 | 30616 |    30616 |      |       |     . |          |                            |
|    33 |                TABLE ACCESS BY INDEX ROWID           | NFND_LOOKUP_LINES              |       1 |    1 |      2027 |     +4 | 30616 |    30616 |      |       |     . |          |                            |
|    34 |            TABLE ACCESS BY INDEX ROWID BATCHED       | GL_BALANCES                    |       1 |    4 |      1635 |     +4 | 47093 |    50422 |   10 | 81920 |     . |     0.10 | Cpu (2)                    |
|    35 |             INDEX RANGE SCAN                         | GL_BALANCES_N5                 |       1 |    3 |      1635 |     +4 | 47093 |    50422 | 1633 |  13MB |     . |     0.15 | gc current block 2-way (2) |
|       |                                                      |                                |         |      |           |        |       |          |      |       |       |          | Cpu (1)                    |
|    36 |              INLIST ITERATOR                         |                                |         |      |           |        | 25167 |          |      |       |     . |          |                            |
|    37 |               INDEX RANGE SCAN                       | NGL_INVAILD_SEGMENT_HISTORY_N1 |       1 |      |         1 |  +1442 | 50334 |        0 |      |       |     . |     0.05 | Cpu (1)                    |
|    38 |          INDEX UNIQUE SCAN                           | GL_LEDGERS_U2                  |       1 |      |           |        |       |          |      |       |     . |          |                            |
|    39 |         TABLE ACCESS BY INDEX ROWID                  | GL_LEDGERS                     |       1 |    1 |           |        |       |          |      |       |     . |          |                            |
|    40 |        TABLE ACCESS BY INDEX ROWID BATCHED           | GL_LEDGERS                     |       1 |    1 |           |        |       |          |      |       |     . |          |                            |
|    41 |         INDEX RANGE SCAN                             | GL_LEDGERS_N1                  |       1 |      |           |        |       |          |      |       |     . |          |                            |
|    42 |      JOIN FILTER USE                                 | :BF0000                        |    7472 |   71 |           |        |       |          |      |       |     . |          |                            |
|    43 |       MAT_VIEW ACCESS STORAGE FULL                   | NCM_BU_DEPARTMENT_MV           |    7472 |   71 |           |        |       |          |      |       |     . |          |                            |
|    44 |     FILTER                                           |                                |         |      |           |        |       |          |      |       |     . |          |                            |
|    45 |      MERGE JOIN CARTESIAN                            |                                |       1 |   83 |           |        |       |          |      |       |     . |          |                            |
|    46 |       HASH JOIN                                      |                                |       1 |   81 |           |        |       |          |      |       |     . |          |                            |
|    47 |        NESTED LOOPS                                  |                                |       1 |   81 |           |        |       |          |      |       |     . |          |                            |
|    48 |         NESTED LOOPS                                 |                                |       1 |   81 |           |        |       |          |      |       |     . |          |                            |
|    49 |          STATISTICS COLLECTOR                        |                                |         |      |           |        |       |          |      |       |     . |          |                            |
|    50 |           HASH JOIN OUTER                            |                                |       1 |   79 |           |        |       |          |      |       |     . |          |                            |
|    51 |            JOIN FILTER CREATE                        | :BF0001                        |       1 |    8 |           |        |       |          |      |       |     . |          |                            |
|    52 |             NESTED LOOPS                             |                                |       1 |    8 |           |        |       |          |      |       |     . |          |                            |
|    53 |              NESTED LOOPS                            |                                |       1 |    8 |           |        |       |          |      |       |     . |          |                            |
|    54 |               NESTED LOOPS OUTER                     |                                |       1 |    7 |           |        |       |          |      |       |     . |          |                            |
|    55 |                NESTED LOOPS                          |                                |       1 |    6 |           |        |       |          |      |       |     . |          |                            |
|    56 |                 NESTED LOOPS                         |                                |       1 |    4 |           |        |       |          |      |       |     . |          |                            |
|    57 |                  NESTED LOOPS                        |                                |       1 |    4 |           |        |       |          |      |       |     . |          |                            |
|    58 |                   NESTED LOOPS                       |                                |       1 |    1 |           |        |       |          |      |       |     . |          |                            |
|    59 |                    INDEX UNIQUE SCAN                 | HR_ALL_ORGANIZATION_UNTS_TL_PK |       1 |    1 |           |        |       |          |      |       |     . |          |                            |
|    60 |                    INDEX UNIQUE SCAN                 | HR_ORGANIZATION_UNITS_PK       |       1 |      |           |        |       |          |      |       |     . |          |                            |
|    61 |                   VIEW                               |                                |       1 |    3 |           |        |       |          |      |       |     . |          |                            |
|    62 |                    SORT UNIQUE                       |                                |       1 |    3 |           |        |       |          |      |       |     . |          |                            |
|    63 |                     TABLE ACCESS STORAGE FULL        | NGL_INVAILD_SEGMENT_HISTORY    |       1 |    2 |           |        |       |          |      |       |     . |          |                            |
|    64 |                  TABLE ACCESS BY INDEX ROWID         | GL_LEDGERS                     |       1 |      |           |        |       |          |      |       |     . |          |                            |
|    65 |                   INDEX UNIQUE SCAN                  | GL_LEDGERS_U2                  |       1 |      |           |        |       |          |      |       |     . |          |                            |
|    66 |                 TABLE ACCESS BY INDEX ROWID BATCHED  | GL_JE_BATCHES                  |       1 |    2 |           |        |       |          |      |       |     . |          |                            |
|    67 |                  INDEX RANGE SCAN                    | GL_JE_BATCHES_N2               |       7 |    2 |           |        |       |          |      |       |     . |          |                            |
|    68 |                TABLE ACCESS BY INDEX ROWID           | GL_JE_HEADERS                  |       1 |    1 |           |        |       |          |      |       |     . |          |                            |
|    69 |                 INDEX UNIQUE SCAN                    | GL_JE_HEADERS_U1               |       1 |    1 |           |        |       |          |      |       |     . |          |                            |
|    70 |               INDEX UNIQUE SCAN                      | GL_CODE_COMBINATIONS_U1        |       1 |    1 |           |        |       |          |      |       |     . |          |                            |
|    71 |              TABLE ACCESS BY INDEX ROWID             | GL_CODE_COMBINATIONS           |       1 |    1 |           |        |       |          |      |       |     . |          |                            |
|    72 |            JOIN FILTER USE                           | :BF0001                        |    7472 |   71 |           |        |       |          |      |       |     . |          |                            |
|    73 |             MAT_VIEW ACCESS STORAGE FULL             | NCM_BU_DEPARTMENT_MV           |    7472 |   71 |           |        |       |          |      |       |     . |          |                            |
|    74 |          INDEX RANGE SCAN                            | HR_ORGANIZATION_INFORMATIO_FK2 |       1 |    1 |           |        |       |          |      |       |     . |          |                            |
|    75 |         TABLE ACCESS BY INDEX ROWID                  | HR_ORGANIZATION_INFORMATION    |       1 |    2 |           |        |       |          |      |       |     . |          |                            |
|    76 |        TABLE ACCESS BY INDEX ROWID BATCHED           | HR_ORGANIZATION_INFORMATION    |       1 |    2 |           |        |       |          |      |       |     . |          |                            |
|    77 |         INDEX RANGE SCAN                             | HR_ORGANIZATION_INFORMATIO_FK2 |       1 |    1 |           |        |       |          |      |       |     . |          |                            |
|    78 |       BUFFER SORT                                    |                                |       1 |   81 |           |        |       |          |      |       |     . |          |                            |
|    79 |        TABLE ACCESS BY INDEX ROWID BATCHED           | HR_ORGANIZATION_INFORMATION    |       1 |    2 |           |        |       |          |      |       |     . |          |                            |
|    80 |         INDEX RANGE SCAN                             | HR_ORGANIZATION_INFORMATION_N1 |       2 |    1 |           |        |       |          |      |       |     . |          |                            |
|    81 |      NESTED LOOPS                                    |                                |       2 |  721 |           |        |       |          |      |       |     . |          |                            |
|    82 |       NESTED LOOPS                                   |                                |       2 |  721 |           |        |       |          |      |       |     . |          |                            |
|    83 |        TABLE ACCESS STORAGE FULL FIRST ROWS          | NFND_LOOKUP_DETAILS            |       2 |  719 |           |        |       |          |      |       |     . |          |                            |
|    84 |        INDEX UNIQUE SCAN                             | NFND_LOOKUP_LINES_U1           |       1 |      |           |        |       |          |      |       |     . |          |                            |
|    85 |       TABLE ACCESS BY INDEX ROWID                    | NFND_LOOKUP_LINES              |       1 |    1 |           |        |       |          |      |       |     . |          |                            |
=========================================================================================================================================================================================================================

找到SQL性能瓶颈之后就好办了

优化方法一:建索引,但是这是客户的生产环境,不好随意创建,暂时放弃

 
create index  CUST_GENERAL.NFND_LOOKUP_DETAILS_U2 on CUST_GENERAL.NFND_LOOKUP_DETAILS(DETAIL_CODE);

优化方法二:将exists(col1=xxx or col2=xxx) 改写为 in的写法:

with x1 as (SELECT  /*+ materialize */ DETAIL_CODE
          FROM NFND_LOOKUP_LINES NLL, NFND_LOOKUP_DETAILS NLD
         WHERE NLD.LINE_CODE = NLL.LINE_CODE
           AND SYSDATE BETWEEN NVL(NLL.START_DATE_ACTIVE, SYSDATE) AND
               NVL(NLL.END_DATE_ACTIVE, SYSDATE)
           AND NVL(NLL.ENABLED_FLAG, 'N') = 'Y'
           AND NLL.LOOKUP_TYPE = 'NGL_SUBAC_IC_MAPPING')     
SELECT  GCC.SEGMENT1,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 1, GCC.SEGMENT1) SEGMENT1_DESC,
       GCC.SEGMENT3,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 3, GCC.SEGMENT3) SEGMENT3_DESC,
       GCC.SEGMENT2,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 2, GCC.SEGMENT2) SEGMENT2_DESC,
       NBD.BUSSION_CODE,
       NBD.BUSSION_NAME,
       GCC.SEGMENT4,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 4, GCC.SEGMENT4) SEGMENT4_DESC,
       GCC.SEGMENT5,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 5, GCC.SEGMENT5) SEGMENT5_DESC,
       GCC.SEGMENT6,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 6, GCC.SEGMENT6) SEGMENT6_DESC,
       GCC.SEGMENT7,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 7, GCC.SEGMENT7) SEGMENT7_DESC,
       GCC.SEGMENT8,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 8, GCC.SEGMENT8) SEGMENT8_DESC,
       DECODE(GBL.CURRENCY_CODE,
              GLE.CURRENCY_CODE,
              (NVL(GBL.BEGIN_BALANCE_DR_BEQ, 0) -
              NVL(GBL.BEGIN_BALANCE_CR_BEQ, 0) +
              NVL(GBL.PERIOD_NET_DR_BEQ, 0) - NVL(GBL.PERIOD_NET_CR_BEQ, 0)),
              (NVL(GBL.BEGIN_BALANCE_DR, 0) - NVL(GBL.BEGIN_BALANCE_CR, 0) +
              NVL(GBL.PERIOD_NET_DR, 0) - NVL(GBL.PERIOD_NET_CR, 0))) END_AMT,
       DECODE(GBL.CURRENCY_CODE,
              GLE.CURRENCY_CODE,
              (NVL(GBL.BEGIN_BALANCE_DR_BEQ, 0) -
              NVL(GBL.BEGIN_BALANCE_CR_BEQ, 0) +
              NVL(GBL.PERIOD_NET_DR_BEQ, 0) - NVL(GBL.PERIOD_NET_CR_BEQ, 0)),
              (NVL(GBL.BEGIN_BALANCE_DR_BEQ, 0) -
              NVL(GBL.BEGIN_BALANCE_CR_BEQ, 0) +
              NVL(GBL.PERIOD_NET_DR_BEQ, 0) - NVL(GBL.PERIOD_NET_CR_BEQ, 0))) END_AMT_BEQ,
       GBL.CURRENCY_CODE,
       GCC.SEGMENT9,
       GCC.CODE_COMBINATION_ID,
       (SELECT TO_DATE(MAX(FLV.ATTRIBUTE34), 'YYYY/MM/DD HH24:mi:ss') INV_DATE
          FROM FND_FLEX_VALUES_VL FLV
         WHERE FLV.ENABLED_FLAG = 'Y'
           AND (FLV.FLEX_VALUE = GCC.SEGMENT4 OR
               FLV.FLEX_VALUE = GCC.SEGMENT5)
           AND FLV.ATTRIBUTE34 IS NOT NULL) INV_DATE,
       GLE.CURRENCY_CODE CURRENCY_CODE_BEQ,
       NULL NAME,
       '未入账' POST_STATUS,
       'Y' TYPE
  FROM GL_BALANCES          GBL,
       GL_CODE_COMBINATIONS GCC,
       NCM_BU_DEPARTMENT_V  NBD,
       HR_OPERATING_UNITS   HOU,
       GL_LEDGERS           GLE
 WHERE GBL.LEDGER_ID = GLE.LEDGER_ID
   AND GBL.CODE_COMBINATION_ID = GCC.CODE_COMBINATION_ID
   AND GCC.SEGMENT2 = NBD.DEPARTMENT_CODE(+)
   AND GBL.PERIOD_NAME = '2022-09'
   AND GCC.SEGMENT1 = HOU.SHORT_CODE
   AND (GCC.SEGMENT4 IN (SELECT DETAIL_CODE FROM X1) OR 
       GCC.SEGMENT5 IN (SELECT DETAIL_CODE FROM X1))  
   AND NOT EXISTS
 (SELECT 1
          FROM CUST_GENERAL.NGL_INVAILD_SEGMENT_HISTORY T
         WHERE (GCC.SEGMENT4 = T.SEGMENT4_5 OR GCC.SEGMENT5 = T.SEGMENT4_5)
           AND GBL.CURRENCY_CODE = T.CURRENCY_CODE
           AND GCC.SEGMENT1 = T.SEGMENT1)
   AND GCC.SUMMARY_FLAG = 'N'
   AND GLE.LEDGER_CATEGORY_CODE = 'PRIMARY'
   AND GLE.CHART_OF_ACCOUNTS_ID = 50368
   AND XY_COM_DEPT_READ.COM_READ(HOU.ORGANIZATION_ID) = 'Y'
   AND (95 IS NULL OR HOU.ORGANIZATION_ID = 95)
UNION ALL
SELECT GCC.SEGMENT1,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 1, GCC.SEGMENT1) SEGMENT1_DESC,
       GCC.SEGMENT3,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 3, GCC.SEGMENT3) SEGMENT3_DESC,
       GCC.SEGMENT2,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 2, GCC.SEGMENT2) SEGMENT2_DESC,
       NBD.BUSSION_CODE,
       NBD.BUSSION_NAME,
       GCC.SEGMENT4,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 4, GCC.SEGMENT4) SEGMENT4_DESC,
       GCC.SEGMENT5,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 5, GCC.SEGMENT5) SEGMENT5_DESC,
       GCC.SEGMENT6,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 6, GCC.SEGMENT6) SEGMENT6_DESC,
       GCC.SEGMENT7,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 7, GCC.SEGMENT7) SEGMENT7_DESC,
       GCC.SEGMENT8,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 8, GCC.SEGMENT8) SEGMENT8_DESC,
       NIH.END_AMT,
       NIH.END_AMT_BEQ,
       NIH.CURRENCY_CODE,
       GCC.SEGMENT9,
       GCC.CODE_COMBINATION_ID,
       NULL INV_DATE,
       GLE.CURRENCY_CODE CURRENCY_CODE_BEQ,
       GJB.NAME NAME,
       DECODE(GJH.ACCRUAL_REV_STATUS,
              'R',
              '已冲销',
              DECODE(GJH.STATUS,
                     'P',
                     '已过账',
                     'U',
                     '未过账',
                     NULL,
                     '已删除')) POST_STATUS,
       'N' TYPE
  FROM GL_JE_HEADERS GJH,
       GL_JE_BATCHES GJB,
       GL_CODE_COMBINATIONS GCC,
       GL_LEDGERS GLE,
       NCM_BU_DEPARTMENT_V NBD,
       HR_OPERATING_UNITS HOU,
       (SELECT DISTINCT T.JE_HEADER_ID,
                        T.JE_LINE_NUM,
                        T.CODE_COMBINATION_ID,
                        T.POST_GROUP_ID,
                        T.END_AMT,
                        T.END_AMT_BEQ,
                        T.CURRENCY_CODE,
                        T.LEDGER_ID,
                        T.PERIOD_NAME
          FROM CUST_GENERAL.NGL_INVAILD_SEGMENT_HISTORY T) NIH
 WHERE NIH.CODE_COMBINATION_ID = GCC.CODE_COMBINATION_ID
   AND NIH.POST_GROUP_ID = GJB.GROUP_ID
   AND NIH.LEDGER_ID = GLE.LEDGER_ID
   AND GCC.SEGMENT1 = HOU.SHORT_CODE
   AND NIH.JE_HEADER_ID = GJH.JE_HEADER_ID(+)
   AND GCC.SEGMENT2 = NBD.DEPARTMENT_CODE(+)
   AND NIH.PERIOD_NAME = '2022-09'
   AND (GCC.SEGMENT4 IN (SELECT DETAIL_CODE FROM X1) OR 
       GCC.SEGMENT5 IN (SELECT DETAIL_CODE FROM X1))  
   AND XY_COM_DEPT_READ.COM_READ(HOU.ORGANIZATION_ID) = 'Y'
   AND (95 IS NULL OR HOU.ORGANIZATION_ID = 95)
 ORDER BY SEGMENT1, CURRENCY_CODE, INV_DATE;
 

改写完之后跑200多秒,in的写法Oracle优化器会自动将SQL改写为union all

优化方法三:将exists(col1=xxx or col2=xxx) 改写为 left join 的写法:

with x1 as (SELECT  /*+ materialize */ DETAIL_CODE
          FROM NFND_LOOKUP_LINES NLL, NFND_LOOKUP_DETAILS NLD
         WHERE NLD.LINE_CODE = NLL.LINE_CODE
           AND SYSDATE BETWEEN NVL(NLL.START_DATE_ACTIVE, SYSDATE) AND
               NVL(NLL.END_DATE_ACTIVE, SYSDATE)
           AND NVL(NLL.ENABLED_FLAG, 'N') = 'Y'
           AND NLL.LOOKUP_TYPE = 'NGL_SUBAC_IC_MAPPING'
           GROUP BY DETAIL_CODE)     
SELECT  GCC.SEGMENT1,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 1, GCC.SEGMENT1) SEGMENT1_DESC,
       GCC.SEGMENT3,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 3, GCC.SEGMENT3) SEGMENT3_DESC,
       GCC.SEGMENT2,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 2, GCC.SEGMENT2) SEGMENT2_DESC,
       NBD.BUSSION_CODE,
       NBD.BUSSION_NAME,
       GCC.SEGMENT4,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 4, GCC.SEGMENT4) SEGMENT4_DESC,
       GCC.SEGMENT5,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 5, GCC.SEGMENT5) SEGMENT5_DESC,
       GCC.SEGMENT6,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 6, GCC.SEGMENT6) SEGMENT6_DESC,
       GCC.SEGMENT7,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 7, GCC.SEGMENT7) SEGMENT7_DESC,
       GCC.SEGMENT8,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 8, GCC.SEGMENT8) SEGMENT8_DESC,
       DECODE(GBL.CURRENCY_CODE,
              GLE.CURRENCY_CODE,
              (NVL(GBL.BEGIN_BALANCE_DR_BEQ, 0) -
              NVL(GBL.BEGIN_BALANCE_CR_BEQ, 0) +
              NVL(GBL.PERIOD_NET_DR_BEQ, 0) - NVL(GBL.PERIOD_NET_CR_BEQ, 0)),
              (NVL(GBL.BEGIN_BALANCE_DR, 0) - NVL(GBL.BEGIN_BALANCE_CR, 0) +
              NVL(GBL.PERIOD_NET_DR, 0) - NVL(GBL.PERIOD_NET_CR, 0))) END_AMT,
       DECODE(GBL.CURRENCY_CODE,
              GLE.CURRENCY_CODE,
              (NVL(GBL.BEGIN_BALANCE_DR_BEQ, 0) -
              NVL(GBL.BEGIN_BALANCE_CR_BEQ, 0) +
              NVL(GBL.PERIOD_NET_DR_BEQ, 0) - NVL(GBL.PERIOD_NET_CR_BEQ, 0)),
              (NVL(GBL.BEGIN_BALANCE_DR_BEQ, 0) -
              NVL(GBL.BEGIN_BALANCE_CR_BEQ, 0) +
              NVL(GBL.PERIOD_NET_DR_BEQ, 0) - NVL(GBL.PERIOD_NET_CR_BEQ, 0))) END_AMT_BEQ,
       GBL.CURRENCY_CODE,
       GCC.SEGMENT9,
       GCC.CODE_COMBINATION_ID,
       (SELECT TO_DATE(MAX(FLV.ATTRIBUTE34), 'YYYY/MM/DD HH24:mi:ss') INV_DATE
          FROM FND_FLEX_VALUES_VL FLV
         WHERE FLV.ENABLED_FLAG = 'Y'
           AND (FLV.FLEX_VALUE = GCC.SEGMENT4 OR
               FLV.FLEX_VALUE = GCC.SEGMENT5)
           AND FLV.ATTRIBUTE34 IS NOT NULL) INV_DATE,
       GLE.CURRENCY_CODE CURRENCY_CODE_BEQ,
       NULL NAME,
       '未入账' POST_STATUS,
       'Y' TYPE
  FROM GL_BALANCES          GBL,
       GL_CODE_COMBINATIONS GCC,
       NCM_BU_DEPARTMENT_V  NBD,
       HR_OPERATING_UNITS   HOU,
       GL_LEDGERS           GLE,
       X1 X11,
       X1 X12
 WHERE GBL.LEDGER_ID = GLE.LEDGER_ID
   AND GBL.CODE_COMBINATION_ID = GCC.CODE_COMBINATION_ID
   AND GCC.SEGMENT2 = NBD.DEPARTMENT_CODE(+)
   AND GBL.PERIOD_NAME = '2022-09'
   AND GCC.SEGMENT1 = HOU.SHORT_CODE
   AND GCC.SEGMENT4=X11.DETAIL_CODE(+)
   AND GCC.SEGMENT5=X12.DETAIL_CODE(+)
   AND (X11.DETAIL_CODE IS NOT NULL OR X12.DETAIL_CODE IS NOT NULL)    
   AND NOT EXISTS
 (SELECT 1
          FROM CUST_GENERAL.NGL_INVAILD_SEGMENT_HISTORY T
         WHERE (GCC.SEGMENT4 = T.SEGMENT4_5 OR GCC.SEGMENT5 = T.SEGMENT4_5)
           AND GBL.CURRENCY_CODE = T.CURRENCY_CODE
           AND GCC.SEGMENT1 = T.SEGMENT1)
   AND GCC.SUMMARY_FLAG = 'N'
   AND GLE.LEDGER_CATEGORY_CODE = 'PRIMARY'
   AND GLE.CHART_OF_ACCOUNTS_ID = 50368
   AND XY_COM_DEPT_READ.COM_READ(HOU.ORGANIZATION_ID) = 'Y'
   AND (95 IS NULL OR HOU.ORGANIZATION_ID = 95)
UNION ALL
SELECT GCC.SEGMENT1,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 1, GCC.SEGMENT1) SEGMENT1_DESC,
       GCC.SEGMENT3,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 3, GCC.SEGMENT3) SEGMENT3_DESC,
       GCC.SEGMENT2,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 2, GCC.SEGMENT2) SEGMENT2_DESC,
       NBD.BUSSION_CODE,
       NBD.BUSSION_NAME,
       GCC.SEGMENT4,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 4, GCC.SEGMENT4) SEGMENT4_DESC,
       GCC.SEGMENT5,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 5, GCC.SEGMENT5) SEGMENT5_DESC,
       GCC.SEGMENT6,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 6, GCC.SEGMENT6) SEGMENT6_DESC,
       GCC.SEGMENT7,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 7, GCC.SEGMENT7) SEGMENT7_DESC,
       GCC.SEGMENT8,
       GL_FLEXFIELDS_PKG.GET_DESCRIPTION_SQL(50368, 8, GCC.SEGMENT8) SEGMENT8_DESC,
       NIH.END_AMT,
       NIH.END_AMT_BEQ,
       NIH.CURRENCY_CODE,
       GCC.SEGMENT9,
       GCC.CODE_COMBINATION_ID,
       NULL INV_DATE,
       GLE.CURRENCY_CODE CURRENCY_CODE_BEQ,
       GJB.NAME NAME,
       DECODE(GJH.ACCRUAL_REV_STATUS,
              'R',
              '已冲销',
              DECODE(GJH.STATUS,
                     'P',
                     '已过账',
                     'U',
                     '未过账',
                     NULL,
                     '已删除')) POST_STATUS,
       'N' TYPE
  FROM GL_JE_HEADERS GJH,
       GL_JE_BATCHES GJB,
       GL_CODE_COMBINATIONS GCC,
       GL_LEDGERS GLE,
       NCM_BU_DEPARTMENT_V NBD,
       HR_OPERATING_UNITS HOU,
       (SELECT DISTINCT T.JE_HEADER_ID,
                        T.JE_LINE_NUM,
                        T.CODE_COMBINATION_ID,
                        T.POST_GROUP_ID,
                        T.END_AMT,
                        T.END_AMT_BEQ,
                        T.CURRENCY_CODE,
                        T.LEDGER_ID,
                        T.PERIOD_NAME
          FROM CUST_GENERAL.NGL_INVAILD_SEGMENT_HISTORY T) NIH
       X1 X11,
       X1 X12   
 WHERE NIH.CODE_COMBINATION_ID = GCC.CODE_COMBINATION_ID
   AND NIH.POST_GROUP_ID = GJB.GROUP_ID
   AND NIH.LEDGER_ID = GLE.LEDGER_ID
   AND GCC.SEGMENT1 = HOU.SHORT_CODE
   AND NIH.JE_HEADER_ID = GJH.JE_HEADER_ID(+)
   AND GCC.SEGMENT2 = NBD.DEPARTMENT_CODE(+)
   AND NIH.PERIOD_NAME = '2022-09'
   AND GCC.SEGMENT4=X11.DETAIL_CODE(+)
   AND GCC.SEGMENT5=X12.DETAIL_CODE(+)
   AND (X11.DETAIL_CODE IS NOT NULL OR X12.DETAIL_CODE IS NOT NULL)  
   AND XY_COM_DEPT_READ.COM_READ(HOU.ORGANIZATION_ID) = 'Y'
   AND (95 IS NULL OR HOU.ORGANIZATION_ID = 95)
 ORDER BY SEGMENT1, CURRENCY_CODE, INV_DATE

改写完之后跑100多秒,当然了这条SQL还有其他地方有性能问题,这里就不提了,不是本文主题

上面SQL比较复杂,我们把SQL简化一下,再看看执行计划吧

注意:因为生产环境不能创建索引,所以我把SQL改成了with as了,如果可以创建就不要改写

模拟原始SQL

with x1 as
 (SELECT /*+ materialize */
   DETAIL_CODE
    FROM NFND_LOOKUP_LINES NLL, NFND_LOOKUP_DETAILS NLD
   WHERE NLD.LINE_CODE = NLL.LINE_CODE
     AND SYSDATE BETWEEN NVL(NLL.START_DATE_ACTIVE, SYSDATE) AND
         NVL(NLL.END_DATE_ACTIVE, SYSDATE)
     AND NVL(NLL.ENABLED_FLAG, 'N') = 'Y'
     AND NLL.LOOKUP_TYPE = 'NGL_SUBAC_IC_MAPPING'
   GROUP BY DETAIL_CODE)
select /*mark0*/
 *
  from GL_CODE_COMBINATIONS GCC
 where code_combination_id >= 1000
   and code_combination_id <= 40000
   and exists
 (SELECT 1
          FROM x1
         WHERE (GCC.SEGMENT4 = DETAIL_CODE OR GCC.SEGMENT5 = DETAIL_CODE));

---------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                  | Name                        | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                           |                             |      1 |        |      1 |00:01:08.39 |    3441 |       |       |          |
|   1 |  TEMP TABLE TRANSFORMATION                 |                             |      1 |        |      1 |00:01:08.39 |    3441 |       |       |          |
|   2 |   LOAD AS SELECT (CURSOR DURATION MEMORY)  | SYS_TEMP_2FD9E17B0_AB88E2C6 |      1 |        |      0 |00:00:00.07 |    2683 |  1024 |  1024 |          |
|   3 |    HASH GROUP BY                           |                             |      1 |  89289 |    135K|00:00:00.05 |    2682 |  9382K|  4693K|   12M (0)|
|*  4 |     HASH JOIN                              |                             |      1 |  89289 |    135K|00:00:00.03 |    2682 |  5136K|  5136K| 3222K (0)|
|   5 |      JOIN FILTER CREATE                    | :BF0000                     |      1 |     47 |      3 |00:00:00.01 |       3 |       |       |          |
|   6 |       VIEW                                 | VW_GBF_8                    |      1 |     47 |      3 |00:00:00.01 |       3 |       |       |          |
|   7 |        HASH GROUP BY                       |                             |      1 |     47 |      3 |00:00:00.01 |       3 |  4639K|  4639K| 4374K (0)|
|*  8 |         TABLE ACCESS BY INDEX ROWID BATCHED| NFND_LOOKUP_LINES           |      1 |     48 |      3 |00:00:00.01 |       3 |       |       |          |
|*  9 |          INDEX RANGE SCAN                  | NFND_LOOKUP_LINES_U1        |      1 |     95 |      3 |00:00:00.01 |       2 |  1025K|  1025K|          |
|  10 |      JOIN FILTER USE                       | :BF0000                     |      1 |    134K|    135K|00:00:00.02 |    2644 |       |       |          |
|* 11 |       TABLE ACCESS STORAGE FULL            | NFND_LOOKUP_DETAILS         |      1 |    134K|    135K|00:00:00.02 |    2644 |  1025K|  1025K|          |
|* 12 |   FILTER                                   |                             |      1 |        |      1 |00:01:08.32 |     757 |       |       |          |
|  13 |    TABLE ACCESS BY INDEX ROWID BATCHED     | GL_CODE_COMBINATIONS        |      1 |  35810 |  21612 |00:00:00.02 |     757 |       |       |          |
|* 14 |     INDEX RANGE SCAN                       | GL_CODE_COMBINATIONS_02     |      1 |  35810 |  21612 |00:00:00.01 |      73 |  1025K|  1025K|          |
|* 15 |    VIEW                                    |                             |   1086 |  89289 |      1 |00:01:08.30 |       0 |       |       |          |
|  16 |     TABLE ACCESS STORAGE FULL              | SYS_TEMP_2FD9E17B0_AB88E2C6 |   1086 |  89289 |    146M|00:00:05.89 |       0 |  1025K|  1025K|          |
---------------------------------------------------------------------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   4 - access("NLD"."LINE_CODE"="ITEM_1")
   8 - filter((NVL("NLL"."ENABLED_FLAG",'N')='Y' AND NVL("NLL"."END_DATE_ACTIVE",SYSDATE@!)>=SYSDATE@! AND 
              NVL("NLL"."START_DATE_ACTIVE",SYSDATE@!)<=SYSDATE@!))
   9 - access("NLL"."LOOKUP_TYPE"='NGL_SUBAC_IC_MAPPING')
  11 - storage(SYS_OP_BLOOM_FILTER(:BF0000,"NLD"."LINE_CODE"))
       filter(SYS_OP_BLOOM_FILTER(:BF0000,"NLD"."LINE_CODE"))
  12 - filter( IS NOT NULL)
  14 - access("CODE_COMBINATION_ID">=1000 AND "CODE_COMBINATION_ID"<=40000)
  15 - filter(("DETAIL_CODE"=:B1 OR "DETAIL_CODE"=:B2))

模拟改写一

with x1 as
 (SELECT /*+ materialize */
   DETAIL_CODE
    FROM NFND_LOOKUP_LINES NLL, NFND_LOOKUP_DETAILS NLD
   WHERE NLD.LINE_CODE = NLL.LINE_CODE
     AND SYSDATE BETWEEN NVL(NLL.START_DATE_ACTIVE, SYSDATE) AND
         NVL(NLL.END_DATE_ACTIVE, SYSDATE)
     AND NVL(NLL.ENABLED_FLAG, 'N') = 'Y'
     AND NLL.LOOKUP_TYPE = 'NGL_SUBAC_IC_MAPPING'
   GROUP BY DETAIL_CODE)
select /*mark00*/
 *
  from GL_CODE_COMBINATIONS GCC
 where code_combination_id >= 1000
   and code_combination_id <= 40000
   and (GCC.SEGMENT4 IN (SELECT DETAIL_CODE FROM X1) OR
       GCC.SEGMENT5 IN (SELECT DETAIL_CODE FROM X1));

---------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                  | Name                        | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                           |                             |      1 |        |      1 |00:00:00.12 |    4198 |       |       |          |
|   1 |  TEMP TABLE TRANSFORMATION                 |                             |      1 |        |      1 |00:00:00.12 |    4198 |       |       |          |
|   2 |   LOAD AS SELECT (CURSOR DURATION MEMORY)  | SYS_TEMP_2FD9E17DC_AB88E2C6 |      1 |        |      0 |00:00:00.07 |    2683 |  1024 |  1024 |          |
|   3 |    HASH GROUP BY                           |                             |      1 |  89289 |    135K|00:00:00.05 |    2682 |  9382K|  4693K|   12M (0)|
|*  4 |     HASH JOIN                              |                             |      1 |  89289 |    135K|00:00:00.03 |    2682 |  5136K|  5136K| 3222K (0)|
|   5 |      JOIN FILTER CREATE                    | :BF0000                     |      1 |     47 |      3 |00:00:00.01 |       3 |       |       |          |
|   6 |       VIEW                                 | VW_GBF_8                    |      1 |     47 |      3 |00:00:00.01 |       3 |       |       |          |
|   7 |        HASH GROUP BY                       |                             |      1 |     47 |      3 |00:00:00.01 |       3 |  4639K|  4639K| 4374K (0)|
|*  8 |         TABLE ACCESS BY INDEX ROWID BATCHED| NFND_LOOKUP_LINES           |      1 |     48 |      3 |00:00:00.01 |       3 |       |       |          |
|*  9 |          INDEX RANGE SCAN                  | NFND_LOOKUP_LINES_U1        |      1 |     95 |      3 |00:00:00.01 |       2 |  1025K|  1025K|          |
|  10 |      JOIN FILTER USE                       | :BF0000                     |      1 |    134K|    135K|00:00:00.02 |    2644 |       |       |          |
|* 11 |       TABLE ACCESS STORAGE FULL            | NFND_LOOKUP_DETAILS         |      1 |    134K|    135K|00:00:00.02 |    2644 |  1025K|  1025K|          |
|  12 |   VIEW                                     | VW_ORE_C9441FAD             |      1 |  71620 |      1 |00:00:00.05 |    1514 |       |       |          |
|  13 |    UNION-ALL                               |                             |      1 |        |      1 |00:00:00.05 |    1514 |       |       |          |
|* 14 |     HASH JOIN                              |                             |      1 |  35810 |      1 |00:00:00.03 |     757 |  9938K|  4971K|   14M (0)|
|  15 |      VIEW                                  |                             |      1 |  89289 |    135K|00:00:00.01 |       0 |       |       |          |
|  16 |       TABLE ACCESS STORAGE FULL            | SYS_TEMP_2FD9E17DC_AB88E2C6 |      1 |  89289 |    135K|00:00:00.01 |       0 |  1025K|  1025K|          |
|  17 |      TABLE ACCESS BY INDEX ROWID BATCHED   | GL_CODE_COMBINATIONS        |      1 |  35810 |  21612 |00:00:00.01 |     757 |       |       |          |
|* 18 |       INDEX RANGE SCAN                     | GL_CODE_COMBINATIONS_02     |      1 |  35810 |  21612 |00:00:00.01 |      73 |  1025K|  1025K|          |
|* 19 |     FILTER                                 |                             |      1 |        |      0 |00:00:00.03 |     757 |       |       |          |
|* 20 |      HASH JOIN                             |                             |      1 |  35810 |      0 |00:00:00.03 |     757 |  9938K|  4971K|   14M (0)|
|  21 |       VIEW                                 |                             |      1 |  89289 |    135K|00:00:00.01 |       0 |       |       |          |
|  22 |        TABLE ACCESS STORAGE FULL           | SYS_TEMP_2FD9E17DC_AB88E2C6 |      1 |  89289 |    135K|00:00:00.01 |       0 |  1025K|  1025K|          |
|  23 |       TABLE ACCESS BY INDEX ROWID BATCHED  | GL_CODE_COMBINATIONS        |      1 |  35810 |  21612 |00:00:00.01 |     757 |       |       |          |
|* 24 |        INDEX RANGE SCAN                    | GL_CODE_COMBINATIONS_02     |      1 |  35810 |  21612 |00:00:00.01 |      73 |  1025K|  1025K|          |
|* 25 |      VIEW                                  |                             |      0 |      1 |      0 |00:00:00.01 |       0 |       |       |          |
|  26 |       TABLE ACCESS STORAGE FULL            | SYS_TEMP_2FD9E17DC_AB88E2C6 |      0 |  89289 |      0 |00:00:00.01 |       0 |  1025K|  1025K|          |
---------------------------------------------------------------------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   4 - access("NLD"."LINE_CODE"="ITEM_1")
   8 - filter((NVL("NLL"."ENABLED_FLAG",'N')='Y' AND NVL("NLL"."END_DATE_ACTIVE",SYSDATE@!)>=SYSDATE@! AND 
              NVL("NLL"."START_DATE_ACTIVE",SYSDATE@!)<=SYSDATE@!))
   9 - access("NLL"."LOOKUP_TYPE"='NGL_SUBAC_IC_MAPPING')
  11 - storage(SYS_OP_BLOOM_FILTER(:BF0000,"NLD"."LINE_CODE"))
       filter(SYS_OP_BLOOM_FILTER(:BF0000,"NLD"."LINE_CODE"))
  14 - access("GCC"."SEGMENT4"="DETAIL_CODE")
  18 - access("CODE_COMBINATION_ID">=1000 AND "CODE_COMBINATION_ID"<=40000)
  19 - filter(LNNVL( IS NOT NULL))
  20 - access("GCC"."SEGMENT5"="DETAIL_CODE")
  24 - access("CODE_COMBINATION_ID">=1000 AND "CODE_COMBINATION_ID"<=40000)
  25 - filter("DETAIL_CODE"=:B1)

模拟改写二

with x1 as
 (SELECT /*+ materialize */
   DETAIL_CODE
    FROM NFND_LOOKUP_LINES NLL, NFND_LOOKUP_DETAILS NLD
   WHERE NLD.LINE_CODE = NLL.LINE_CODE
     AND SYSDATE BETWEEN NVL(NLL.START_DATE_ACTIVE, SYSDATE) AND
         NVL(NLL.END_DATE_ACTIVE, SYSDATE)
     AND NVL(NLL.ENABLED_FLAG, 'N') = 'Y'
     AND NLL.LOOKUP_TYPE = 'NGL_SUBAC_IC_MAPPING'
	 GROUP BY DETAIL_CODE)
select /*mark000*/ gcc.*
  from GL_CODE_COMBINATIONS GCC
  left join x1 x11
    on gcc.segment4 = x11.detail_code
  left join x1 x12
    on gcc.segment5 = x12.detail_code
 where code_combination_id >= 1000
   and code_combination_id <= 40000
   and (x11.detail_code is not null or x12.detail_code is not null);

---------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                  | Name                        | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                           |                             |      1 |        |      1 |00:00:00.12 |    3405 |       |       |          |
|   1 |  TEMP TABLE TRANSFORMATION                 |                             |      1 |        |      1 |00:00:00.12 |    3405 |       |       |          |
|   2 |   LOAD AS SELECT (CURSOR DURATION MEMORY)  | SYS_TEMP_2FD9E17E2_AB88E2C6 |      1 |        |      0 |00:00:00.07 |    2647 |  1024 |  1024 |          |
|   3 |    HASH GROUP BY                           |                             |      1 |  89289 |    135K|00:00:00.05 |    2646 |  9382K|  4693K|   12M (0)|
|*  4 |     HASH JOIN                              |                             |      1 |  89289 |    135K|00:00:00.03 |    2646 |  5136K|  5136K| 3222K (0)|
|   5 |      JOIN FILTER CREATE                    | :BF0000                     |      1 |     47 |      3 |00:00:00.01 |       3 |       |       |          |
|   6 |       VIEW                                 | VW_GBF_8                    |      1 |     47 |      3 |00:00:00.01 |       3 |       |       |          |
|   7 |        HASH GROUP BY                       |                             |      1 |     47 |      3 |00:00:00.01 |       3 |  4639K|  4639K| 4376K (0)|
|*  8 |         TABLE ACCESS BY INDEX ROWID BATCHED| NFND_LOOKUP_LINES           |      1 |     48 |      3 |00:00:00.01 |       3 |       |       |          |
|*  9 |          INDEX RANGE SCAN                  | NFND_LOOKUP_LINES_U1        |      1 |     95 |      3 |00:00:00.01 |       2 |  1025K|  1025K|          |
|  10 |      JOIN FILTER USE                       | :BF0000                     |      1 |    134K|    135K|00:00:00.02 |    2643 |       |       |          |
|* 11 |       TABLE ACCESS STORAGE FULL            | NFND_LOOKUP_DETAILS         |      1 |    134K|    135K|00:00:00.02 |    2643 |  1025K|  1025K|          |
|* 12 |   FILTER                                   |                             |      1 |        |      1 |00:00:00.05 |     757 |       |       |          |
|* 13 |    HASH JOIN RIGHT OUTER                   |                             |      1 |  35810 |  21612 |00:00:00.05 |     757 |  9938K|  4971K|   14M (0)|
|  14 |     VIEW                                   |                             |      1 |  89289 |    135K|00:00:00.01 |       0 |       |       |          |
|  15 |      TABLE ACCESS STORAGE FULL             | SYS_TEMP_2FD9E17E2_AB88E2C6 |      1 |  89289 |    135K|00:00:00.01 |       0 |  1025K|  1025K|          |
|* 16 |     HASH JOIN RIGHT OUTER                  |                             |      1 |  35810 |  21612 |00:00:00.03 |     757 |  9938K|  4971K|   14M (0)|
|  17 |      VIEW                                  |                             |      1 |  89289 |    135K|00:00:00.01 |       0 |       |       |          |
|  18 |       TABLE ACCESS STORAGE FULL            | SYS_TEMP_2FD9E17E2_AB88E2C6 |      1 |  89289 |    135K|00:00:00.01 |       0 |  1025K|  1025K|          |
|  19 |      TABLE ACCESS BY INDEX ROWID BATCHED   | GL_CODE_COMBINATIONS        |      1 |  35810 |  21612 |00:00:00.01 |     757 |       |       |          |
|* 20 |       INDEX RANGE SCAN                     | GL_CODE_COMBINATIONS_02     |      1 |  35810 |  21612 |00:00:00.01 |      73 |  1025K|  1025K|          |
---------------------------------------------------------------------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   4 - access("NLD"."LINE_CODE"="ITEM_1")
   8 - filter((NVL("NLL"."ENABLED_FLAG",'N')='Y' AND NVL("NLL"."END_DATE_ACTIVE",SYSDATE@!)>=SYSDATE@! AND 
              NVL("NLL"."START_DATE_ACTIVE",SYSDATE@!)<=SYSDATE@!))
   9 - access("NLL"."LOOKUP_TYPE"='NGL_SUBAC_IC_MAPPING')
  11 - storage(SYS_OP_BLOOM_FILTER(:BF0000,"NLD"."LINE_CODE"))
       filter(SYS_OP_BLOOM_FILTER(:BF0000,"NLD"."LINE_CODE"))
  12 - filter(("X11"."DETAIL_CODE" IS NOT NULL OR "X12"."DETAIL_CODE" IS NOT NULL))
  13 - access("GCC"."SEGMENT5"="X12"."DETAIL_CODE")
  16 - access("GCC"."SEGMENT4"="X11"."DETAIL_CODE")
  20 - access("GCC"."CODE_COMBINATION_ID">=1000 AND "GCC"."CODE_COMBINATION_ID"<=40000)

本案例最终采用的是LEFT JOIN方式改写,因为LEFT JOIN方式改写之后 主数据只扫描一次,子查询扫描2次,如果采用IN改写, 主数据要扫描2次,子查询扫描2次,主数据是通过复杂的关联得到的数据,子查询就是WITH AS的数据,很明显主数据耗费资源多,所以不能让主数据扫描2次

如果你在工作中遇到了类似情况,究竟是创建索引,还是对SQL进行改写,具体问题具体分析

以上是关于SQL优化案例之where exists(col1=xxx or col2=xxx)等价改写的主要内容,如果未能解决你的问题,请参考以下文章

SQL优化案例之where exists(col1=xxx or col2=xxx)等价改写

SQL优化案例之where exists(col1=xxx or col2=xxx)等价改写

SQL优化案例之exists中套or not exists

SQL优化案例之exists中套or not exists

SQL优化案例之exists中套or not exists

SQL优化案例之exists中套or not exists