회사에서 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만 적용을 해 보았습니다. (사실 잘 모름)
그리고 테이블명 옆의 숫자는 해당 테이블의 전체 건 수 임.
(실제 테이블명은 사정상 임의의 테이블명으로 변경을 하였습니다.)
고수 님들의 지도 부탁드립니다.
아직 아무도 댓글이 없어서 제 생각을 말씀 드려보면 결국 INDEX를 만들어서 처리를 해야 할 듯 한데 그전에 같은 테이블을 여러번 읽고 있는 비효율이 있어서
혹시 그 부분을 구체적으로 어떻게 수정하면 좋을 지에 대한 조언을 부탁드립니다.
tbl01 테이블에 (un_d_cd, ano, a_sno) 인덱스가 필요합니다.
tbl10 테이블에 (ano, a_sno) 인덱스가 필요합니다.
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'
;
드디어 답을 주셨네요 . 끝까지 읽기도 전에 신기함에 흥분해서 키보드 치는 손이 떨립니다.
내일 당장 회사에 가서 반영해 보고 내용 올리겠습니다.
개발서버에 적용 후 역시나 깜짝 놀랐습니다.(겁나 빠른 속도에 음 ~~~~ 말씀하신 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를 추천 해 주실 수 있을까요? 한번에 이해를 하기에는 배움이 부족하네요
원하는 답을 주신 것도 황송하나 부족한 부분을 채우고 싶습니다.
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'
;
개인적인 일로 어제는 로그인을 하지 못하고 이제야 접속 해 보니 또 답을 주셨습니다.
우선 감사 드리며 지난번에 달아 주신 답변과 약간 차이가 있어 질문 합니다.
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) 이렇게 하신 것으로 예상 했는데
있어야 하지 않은가 하는 짧은 생각이 듭니다.
그리고 다시 한번 감사드립니다.
해당 조건은 다음 조건으로 대체했습니다.
AND t11.상품가입일 IS NOT NULL
답을 어제 주셨군요
금일 회사에 가서 한줄씩 줄여 가면서 확인을 해보니 말씀하신 대로 없어도 되는 아니 대체 된 걸 결과로 확인 했습니다.
다시 한번 제 무지가 탄로가 났네요 감사합니다.