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)等价改写