대량 데이터 OUTER JOIN 조회 0 9 3,108

by 구사일생 [SQL Query] 대량 데이터 OUTER JOIN 대량건조회힌트 [2023.08.11 21:15:18]


회사에서 SYBASE를 오라클(엑사 19C)로 변경하는 작업을 진행 중 입니다.

SYBASE에서는 10 ~20분 정도 걸리는 SQL이 오라클에서는 1시간 이상이 걸립니다.

WITH T_2222 AS (
SELECT /*+ FULL(A) PARALLEL(A 4)*/
       ANO,A_SNO,MAX(UN_SQN) AS MX_S_NO
  FROM TBL01 A  --68854922
 WHERE 1=1
   AND UN_D_CD = '2125'
GROUP BY ANO,A_SNO
)
,T_3333 AS (
SELECT /*+ FULL(A) PARALLEL(A 4)*/
       ANO,A_SNO,MAX(UN_SQN) AS MX_S_NO
  FROM TBL01 A  --68854922
 WHERE 1=1
   AND UN_D_CD = '5071'
   AND TT05 = 'E3'
GROUP BY ANO,A_SNO
)
SELECT 
        T10.ANO
      , T10.A_SNO
      , T10.CNO
      , CASE WHEN TRIM(T11.LST_D) = '1' THEN 'Y' ELSE 'N' END
      , CASE WHEN TRIM(T12.LST_D) = '1' THEN 'Y' ELSE 'N' END
      , CASE WHEN TRIM(T13.LST_D) = '1' THEN 'Y' ELSE 'N' END
      , TRIM(C11.CNM)
      , TRIM(C12.CD_NM)
  FROM (SELECT /*+ FULL(A) PARALLEL(A 4)*/
              ANO,A_SNO,CNO,ACT_DV_CD,TDT,PCD,PRD_BAL
          FROM TBL10 A  --186839964
        ) T10
         LEFT OUTER 
         JOIN (
                SELECT /*+ FULL(A) PARALLEL(A 4)*/
                       ANO,A_SNO,LST_D,REG_DT,TT01,UN_D_CD
                  FROM TBL01 A  --68854922
              ) T11
           ON T11.ANO = T10.ANO
          AND T11.A_SNO = T10.A_SNO
          AND T11.UN_D_CD = '9225'
          AND T11.TT01 = 'E3'
          AND T11.LST_D = '1'
         LEFT OUTER 
         JOIN T_2222 T22
           ON T22.ANO = T10.ANO
          AND T22.A_SNO = T10.A_SNO
         LEFT OUTER 
         JOIN (
                SELECT /*+ FULL(A) PARALLEL(A 4)*/
                       ANO,A_SNO,LST_D,REG_DT,TT01,UN_D_CD
                  FROM TBL01 A  --68854922
              ) T12
           ON T12.ANO = T22.ANO
          AND T12.A_SNO = T22.A_SNO
          AND T12.UN_D_CD = T22.MX_S_NO
         LEFT OUTER 
         JOIN T_3333 T23
           ON T23.ANO = T10.ANO
          AND T23.A_SNO = T10.A_SNO
         LEFT OUTER 
         JOIN (
                SELECT /*+ FULL(A) PARALLEL(A 4)*/
                       ANO,A_SNO,LST_D,REG_DT,TT01,UN_D_CD
                  FROM TBL01 A  --68854922
              ) T13
           ON T13.ANO = T23.ANO
          AND T13.A_SNO = T23.A_SNO
          AND T13.UN_D_CD = T23.MX_S_NO
         LEFT OUTER 
         JOIN (
                SELECT /*+ FULL(A) PARALLEL(A 4)*/
                       PRD_KORN_NM,PCD,PRD_APCL_ST_CD
                  FROM TBL02 A  --41064
              ) C10
           ON C10.PCD = T10.PCD
          AND C10.PRD_APCL_ST_CD = '10'
         LEFT OUTER 
         JOIN (
                SELECT /*+ FULL(A) PARALLEL(A 4)*/
                       CNO,CNM,TPOP_NM,STD_INDS_CLAS_NM,CORP_SCAL_CD
                  FROM TBL03 A  --42119302 
              ) C11
           ON C11.CNO = T10.CNO
         LEFT OUTER 
         JOIN (
                SELECT /*+ FULL(A) PARALLEL(A 4)*/
                       CD_NM,CD,UN,CD_ID
                  FROM TBL04 A  --317780
              ) C12
           ON C12.CD = C11.CORP_SCAL_CD
          AND C12.CD_ID = '13939' 
          AND C12.UN = 'Y'
  WHERE 1=1
     AND ( TRIM(T11.ANO) IS NOT NULL OR TRIM(T12.ANO) IS NOT NULL )
------------------------------------------------------------------------------------------------

T10 테이블이 1억8천만건으로 아웃터 조인 후 마지막에  AND ( TRIM(T11.ANO) IS NOT NULL OR TRIM(T12.ANO) IS NOT NULL ) 이 조건으로 대부분의 데이터가 걸러져서 결국은

매일 1000건 이하가 조회 되어 테이블에 적재 됩니다. (1건도 없는 날도 있음)

배치 프로그램이라 특별한 힌트없이 PARALLEL만 적용을 해 보았습니다. (사실 잘 모름)

그리고 테이블명 옆의 숫자는 해당 테이블의 전체 건 수 임.

(실제 테이블명은 사정상 임의의 테이블명으로 변경을 하였습니다.)

 

고수 님들의 지도 부탁드립니다.

by 구사일생 [2023.08.16 21:40:59]

아직 아무도 댓글이 없어서 제 생각을 말씀 드려보면 결국 INDEX를 만들어서 처리를 해야 할 듯 한데 그전에 같은 테이블을 여러번 읽고 있는 비효율이 있어서 

혹시 그 부분을 구체적으로 어떻게 수정하면 좋을 지에 대한 조언을   부탁드립니다.


by 마농 [2023.08.17 08:46:25]

tbl01 테이블에 (un_d_cd, ano, a_sno) 인덱스가 필요합니다.
tbl10 테이블에 (ano, a_sno) 인덱스가 필요합니다.


by 마농 [2023.08.17 08:31:18]
SELECT t10.ano
     , t10.a_sno
     , t10.cno
     , t11.yn11
     , t11.yn12
     , t11.yn13
     , TRIM(c11.cnm)   nm_11
     , TRIM(c12.cd_nm) nm_12
  FROM tbl10 t10
 INNER JOIN
       (SELECT ano
             , a_sno
             , MAX(DECODE(gb, 11, 'Y', 'N')) yn11
             , MAX(DECODE(gb, 12, 'Y', 'N')) yn12
             , MAX(DECODE(gb, 13, 'Y', 'N')) yn13
          FROM (SELECT 11 gb
                     , ano
                     , a_sno
                  FROM tbl01
                   AND un_d_cd = '9225'
                   AND tt01    = 'E3'
                   AND lst_d   = '1'
                 UNION ALL
                SELECT a.gb
                     , b.ano
                     , b.a_sno
                  FROM (SELECT DECODE(un_d_cd, '2125', 12, '5071', 13) gb
                             , ano
                             , a_sno
                             , MAX(un_sqn) mx_s_no
                          FROM tbl01
                         WHERE (un_d_cd = '2125')
                            OR (un_d_cd = '5071' AND tt05 = 'E3')
                         GROUP BY ano, a_sno, un_d_cd
                        ) a
                 INNER JOIN tbl01 b
                    ON b.ano     = a.ano
                   AND b.a_sno   = a.a_sno
                   AND b.un_d_cd = a.mx_s_no
                   AND b.lst_d   = '1'
                )
         GROUP BY ano, a_sno
        ) t11
    ON t10.ano   = t11.ano
   AND t10.a_sno = t11.a_sno
   AND 'Y' IN (t11.yn11, t11.yn12)
  LEFT OUTER JOIN tbl03 c11
    ON c11.cno   = t10.cno
  LEFT OUTER JOIN tbl04 c12
    ON c12.cd    = c11.corp_scal_cd
   AND c12.cd_id = '13939' 
   AND c12.un    = 'Y'
;

 


by 구사일생 [2023.08.17 21:17:35]

드디어 답을 주셨네요 . 끝까지 읽기도 전에 신기함에 흥분해서 키보드 치는 손이 떨립니다.

내일 당장 회사에 가서 반영해 보고 내용 올리겠습니다.


by 구사일생 [2023.08.18 20:57:11]

개발서버에 적용 후 역시나 깜짝 놀랐습니다.(겁나 빠른 속도에 음 ~~~~ 말씀하신 INDEX는 이미 존재 하여 최상의 효과를 보이는 듯 함.)

역시라는 생각을 했습니다. 사정상 전체 SQL을 올리지 못하고 일부만 줄여서 올렸었는데

SELECT 절의 추가 내용(제외 했었던 부분)을 제가 적용을 해 보려 하였으나 변경하신 내용을 모두 이해 해야 수정이 가능 할 듯 합니다. 해서 나머지 부분도 모두 올립니다.

나머지도 수정 부탁드립니다. 

WITH T_2222 AS (
SELECT /*+ FULL(A) PARALLEL(A 4)*/
       ANO,A_SNO,MAX(UN_SQN) AS MX_S_NO
  FROM TBL01 A  --68854922
 WHERE 1=1
   AND UN_D_CD = '2125'
GROUP BY ANO,A_SNO
)
,T_3333 AS (
SELECT /*+ FULL(A) PARALLEL(A 4)*/
       ANO,A_SNO,MAX(UN_SQN) AS MX_S_NO
  FROM TBL01 A  --68854922
 WHERE 1=1
   AND UN_D_CD = '5071'
   AND TT05 = 'E3'
GROUP BY ANO,A_SNO
)
SELECT 
        T10.ANO
      , T10.A_SNO
      , T10.CNO
      , CASE WHEN TRIM(T11.LST_D) = '1' THEN 'Y' ELSE 'N' END
      , CASE WHEN TRIM(T12.LST_D) = '1' THEN 'Y' ELSE 'N' END
      , CASE WHEN TRIM(T13.LST_D) = '1' THEN 'Y' ELSE 'N' END
      , TRIM(C11.CNM)
      , TRIM(C12.CD_NM)
---------------------추가부분------------------------------------------------------------------------------------------
    , CASE WHEN T11.REG_DT > CASE WHEN TRIM(T12.LST_D) = '1' THEN TRIM(T12.REG_DT) ELSE TRIM(T12.RLS_DT) END
           THEN T11.REG_DT
         ELSE CASE WHEN TRIM(T12.LST_D) = '1' THEN TRIM(T12.REG_DT) ELSE TRIM(T12.RLS_DT) END
       END  AS 상품가입일
    , T11.REG_DT                                                                        AS 계좌개설일
    , CASE WHEN TRIM(T12.LST_D) = '1' THEN TRIM(T12.REG_DT) ELSE TRIM(T12.RLS_DT) END   AS 발급일
    , CASE WHEN TRIM(T13.LST_D) = '1' THEN TRIM(T13.REG_DT) ELSE TRIM(T13.RLS_DT) END   AS 동의일
-----------------------------------------------------------------------------------------------------------------------
  FROM (SELECT /*+ FULL(A) PARALLEL(A 4)*/
              ANO,A_SNO,CNO,ACT_DV_CD,TDT,PCD,PRD_BAL
          FROM TBL10 A  --186839964
        ) T10
         LEFT OUTER 
         JOIN (
                SELECT /*+ FULL(A) PARALLEL(A 4)*/
                       ANO,A_SNO,LST_D,REG_DT,TT01,UN_D_CD
                  FROM TBL01 A  --68854922
              ) T11
           ON T11.ANO = T10.ANO
          AND T11.A_SNO = T10.A_SNO
          AND T11.UN_D_CD = '9225'
          AND T11.TT01 = 'E3'
          AND T11.LST_D = '1'
         LEFT OUTER 
         JOIN T_2222 T22
           ON T22.ANO = T10.ANO
          AND T22.A_SNO = T10.A_SNO
         LEFT OUTER 
         JOIN (
                SELECT /*+ FULL(A) PARALLEL(A 4)*/
                       ANO,A_SNO,LST_D,REG_DT,TT01,UN_D_CD
                  FROM TBL01 A  --68854922
              ) T12
           ON T12.ANO = T22.ANO
          AND T12.A_SNO = T22.A_SNO
          AND T12.UN_D_CD = T22.MX_S_NO
         LEFT OUTER 
         JOIN T_3333 T23
           ON T23.ANO = T10.ANO
          AND T23.A_SNO = T10.A_SNO
         LEFT OUTER 
         JOIN (
                SELECT /*+ FULL(A) PARALLEL(A 4)*/
                       ANO,A_SNO,LST_D,REG_DT,TT01,UN_D_CD
                  FROM TBL01 A  --68854922
              ) T13
           ON T13.ANO = T23.ANO
          AND T13.A_SNO = T23.A_SNO
          AND T13.UN_D_CD = T23.MX_S_NO
         LEFT OUTER 
         JOIN (
                SELECT /*+ FULL(A) PARALLEL(A 4)*/
                       PRD_KORN_NM,PCD,PRD_APCL_ST_CD
                  FROM TBL02 A  --41064
              ) C10
           ON C10.PCD = T10.PCD
          AND C10.PRD_APCL_ST_CD = '10'
         LEFT OUTER 
         JOIN (
                SELECT /*+ FULL(A) PARALLEL(A 4)*/
                       CNO,CNM,TPOP_NM,STD_INDS_CLAS_NM,CORP_SCAL_CD
                  FROM TBL03 A  --42119302 
              ) C11
           ON C11.CNO = T10.CNO
         LEFT OUTER 
         JOIN (
                SELECT /*+ FULL(A) PARALLEL(A 4)*/
                       CD_NM,CD,UN,CD_ID
                  FROM TBL04 A  --317780
              ) C12
           ON C12.CD = C11.CORP_SCAL_CD
          AND C12.CD_ID = '13939' 
          AND C12.UN = 'Y'
  WHERE 1=1
     AND ( TRIM(T11.ANO) IS NOT NULL OR TRIM(T12.ANO) IS NOT NULL )
;

 

PS.혹시 유사한 내용(Sample) 또는  Reference를 추천 해 주실 수 있을까요? 한번에 이해를 하기에는 배움이 부족하네요

    원하는 답을 주신 것도 황송하나 부족한 부분을 채우고 싶습니다.

 

 

 


by 마농 [2023.08.20 23:18:10]
SELECT t10.ano
     , t10.a_sno
     , t10.cno
     , t11.yn11
     , t11.yn12
     , t11.yn13
     , TRIM(c11.cnm)   nm_11
     , TRIM(c12.cd_nm) nm_12
  FROM tbl10 t10
 INNER JOIN
       (SELECT ano
             , a_sno
             , MAX(CASE WHEN lst_d = '1' AND gb = 11 THEN 'Y' ELSE 'N' END) yn11
             , MAX(CASE WHEN lst_d = '1' AND gb = 12 THEN 'Y' ELSE 'N' END) yn12
             , MAX(CASE WHEN lst_d = '1' AND gb = 13 THEN 'Y' ELSE 'N' END) yn13
             , MAX(CASE WHEN gb IN (11, 12) THEN reg_dt END) AS 상품가입일
             , MAX(CASE WHEN gb = 11 THEN reg_dt END) AS 계좌개설일
             , MAX(CASE WHEN gb = 12 THEN reg_dt END) AS 발급일
             , MAX(CASE WHEN gb = 13 THEN reg_dt END) AS 동의일
          FROM (SELECT 11 gb
                     , ano
                     , a_sno
                     , lst_d
                     , reg_dt
                  FROM tbl01
                   AND un_d_cd = '9225'
                   AND tt01    = 'E3'
                   AND lst_d   = '1'
                 UNION ALL
                SELECT a.gb
                     , b.ano
                     , b.a_sno
                     , b.lst_d
                     , CASE WHEN b.lst_d WHEN '1' THEN b.reg_dt ELSE b.rls_dt END reg_dt
                  FROM (SELECT DECODE(un_d_cd, '2125', 12, '5071', 13) gb
                             , ano
                             , a_sno
                             , MAX(un_sqn) mx_s_no
                          FROM tbl01
                         WHERE (un_d_cd = '2125')
                            OR (un_d_cd = '5071' AND tt05 = 'E3')
                         GROUP BY ano, a_sno, un_d_cd
                        ) a
                 INNER JOIN tbl01 b
                    ON b.ano     = a.ano
                   AND b.a_sno   = a.a_sno
                   AND b.un_d_cd = a.mx_s_no
                )
         GROUP BY ano, a_sno
        ) t11
    ON t10.ano   = t11.ano
   AND t10.a_sno = t11.a_sno
   AND t11.상품가입일 IS NOT NULL
  LEFT OUTER JOIN tbl03 c11
    ON c11.cno   = t10.cno
  LEFT OUTER JOIN tbl04 c12
    ON c12.cd    = c11.corp_scal_cd
   AND c12.cd_id = '13939'
   AND c12.un    = 'Y'
;

 


by 구사일생 [2023.08.22 21:36:18]

개인적인 일로 어제는 로그인을 하지 못하고 이제야 접속 해 보니 또 답을 주셨습니다.

우선 감사 드리며 지난번에 달아 주신 답변과 약간 차이가 있어 질문 합니다.

AND 'Y' IN (T11.YN11, T11.YN12) 이런 부분이 있었는데 빠진 것 같은데

아마도 이부분을  AND ( TRIM(T11.ANO) IS NOT NULL OR TRIM(T12.ANO) IS NOT NULL )   ==> AND 'Y' IN (T11.YN11, T11.YN12) 이렇게 하신 것으로 예상 했는데 

있어야 하지 않은가 하는 짧은 생각이 듭니다.

그리고 다시 한번 감사드립니다.


by 마농 [2023.08.22 22:19:41]

해당 조건은 다음 조건으로 대체했습니다.
AND t11.상품가입일 IS NOT NULL


by 구사일생 [2023.08.23 21:03:50]

답을 어제 주셨군요

금일 회사에 가서 한줄씩 줄여 가면서 확인을 해보니 말씀하신 대로 없어도 되는 아니 대체 된 걸 결과로 확인 했습니다.

다시 한번 제 무지가 탄로가 났네요 감사합니다.

 

 

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입