안녕하세요 DB초보입니다.
인라인 뷰를 사용해서 8개의 컬럼으로 된 하나의 행만 추출하려고 합니다.
그런데, 코드의 대부분이 중복됩니다.
PL/SQL을 사용하면 될 것 같은데 PL/SQL을 잘 몰라서 어떻게 접근할지도 모르겠습니다.
'CARD_NUM' 컬럼과 'CARD_TRANSACTION_TIME' 컬럼에 인덱스를 생성해서 쿼리 속도가 많이 향상됐습니다.
그럼에도, 천만건의 데이터를 다루다보니 약간의 지연이 있습니다.
어떻게 하면 코드를 단순화하고 쿼리속도를 향상시킬 수 있을까요?
WITH WHOLE AS (SELECT CARD_TRANSACTION_TIME, CARD_TRANSACTION_AMOUNT, CARD_TRANSACTION_CONTENT, INDUSTRY_CODE
FROM CARD_TRANSACTION_TEST01
WHERE CARD_NUM IN(SELECT CARD_NUM FROM CARD_CONTRACT_TEST01 WHERE RESI_NUM = '9203101937988')
AND TO_CHAR(CARD_TRANSACTION_TIME, 'YYYY') = '2020'
AND TO_CHAR(CARD_TRANSACTION_TIME, 'MM') = '01'
UNION ALL
SELECT CARD_TRANSACTION_TIME, CARD_TRANSACTION_AMOUNT, CARD_TRANSACTION_CONTENT, INDUSTRY_CODE
FROM OPEN_CARD_TRANSACTION_TEST01
WHERE RESI_NUM = '9203101937988'
AND TO_CHAR(CARD_TRANSACTION_TIME, 'YYYY') = '2020'
AND TO_CHAR(CARD_TRANSACTION_TIME, 'MM') = '01'
AND MEANS IN('cardOne', 'cardTwo')
)
SELECT SUBQUERY1.RESULT AS TYPE1, SUBQUERY2.RESULT AS "TYPE2", SUBQUERY3.RESULT AS "TYPE3", SUBQUERY4.RESULT AS "TYPE4",
SUBQUERY5.RESULT AS "TYPE5", SUBQUERY6.RESULT AS "TYPE6", SUBQUERY7.RESULT AS "TYPE7", SUBQUERY8.RESULT AS "TYPE8"
FROM (SELECT *
FROM (SELECT SUM(RESULT) AS RESULT
FROM(
SELECT SUM(CARD_TRANSACTION_AMOUNT) AS RESULT
FROM WHOLE
GROUP BY INDUSTRY_CODE
HAVING INDUSTRY_CODE IN('I1', 'I2')
UNION ALL
-- SELECT NULL AS NUM
SELECT 0 AS RESULT
FROM DUAL))
WHERE RESULT IS NOT NULL OR ROWNUM = 1) SUBQUERY1,
(SELECT *
FROM (SELECT SUM(RESULT) AS RESULT
FROM(
SELECT SUM(CARD_TRANSACTION_AMOUNT) AS RESULT
FROM WHOLE
GROUP BY INDUSTRY_CODE
HAVING INDUSTRY_CODE IN('I4', 'I5', 'I6')
UNION ALL
-- SELECT NULL AS NUM
SELECT 0 AS RESULT
FROM DUAL))
WHERE RESULT IS NOT NULL OR ROWNUM = 1) SUBQUERY2,
(SELECT *
FROM (SELECT SUM(RESULT) AS RESULT
FROM(
SELECT SUM(CARD_TRANSACTION_AMOUNT) AS RESULT
FROM WHOLE
GROUP BY INDUSTRY_CODE
HAVING INDUSTRY_CODE IN('I7', 'I8')
UNION ALL
-- SELECT NULL AS NUM
SELECT 0 AS RESULT
FROM DUAL))
WHERE RESULT IS NOT NULL OR ROWNUM = 1) SUBQUERY3,
(SELECT *
FROM (SELECT SUM(CARD_TRANSACTION_AMOUNT) AS RESULT
FROM WHOLE
GROUP BY INDUSTRY_CODE
HAVING INDUSTRY_CODE IN('I9')
UNION ALL
-- SELECT NULL AS NUM
SELECT 0 AS RESULT
FROM DUAL)
WHERE RESULT IS NOT NULL OR ROWNUM = 1) SUBQUERY4,
(SELECT *
FROM (SELECT SUM(CARD_TRANSACTION_AMOUNT) AS RESULT
FROM WHOLE
GROUP BY INDUSTRY_CODE
HAVING INDUSTRY_CODE IN('I10')
UNION ALL
-- SELECT NULL AS NUM
SELECT 0 AS RESULT
FROM DUAL)
WHERE RESULT IS NOT NULL OR ROWNUM = 1) SUBQUERY5,
(SELECT *
FROM (SELECT SUM(CARD_TRANSACTION_AMOUNT) AS RESULT
FROM WHOLE
GROUP BY INDUSTRY_CODE
HAVING INDUSTRY_CODE IN('I11')
UNION ALL
-- SELECT NULL AS NUM
SELECT 0 AS RESULT
FROM DUAL)
WHERE RESULT IS NOT NULL OR ROWNUM = 1) SUBQUERY6,
(SELECT *
FROM (SELECT SUM(CARD_TRANSACTION_AMOUNT) AS RESULT
FROM WHOLE
GROUP BY INDUSTRY_CODE
HAVING INDUSTRY_CODE IN('I12')
UNION ALL
-- SELECT NULL AS NUM
SELECT 0 AS RESULT
FROM DUAL)
WHERE RESULT IS NOT NULL OR ROWNUM = 1) SUBQUERY7,
(SELECT *
FROM (SELECT SUM(CARD_TRANSACTION_AMOUNT) AS RESULT
FROM WHOLE
GROUP BY INDUSTRY_CODE
HAVING INDUSTRY_CODE IN('I13')
UNION ALL
-- SELECT NULL AS NUM
SELECT 0 AS RESULT
FROM DUAL)
WHERE RESULT IS NOT NULL OR ROWNUM = 1) SUBQUERY8
WHERE ROWNUM <=1;
WITH whole AS
(
-- 1. 컬럼을 가공하여 조건주지 말고 -> 조건을 가공
SELECT industry_code cd
, card_transaction_amount amt
FROM card_transaction_test01
WHERE card_num IN (SELECT card_num FROM card_contract_test01 WHERE resi_num = '9203101937988')
AND card_transaction_time >= TO_DATE('2020'||'01', 'yyyymm')
AND card_transaction_time < ADD_MONTHS(TO_DATE('2020'||'01', 'yyyymm'), 1)
UNION ALL
SELECT industry_code cd
, card_transaction_amount amt
FROM open_card_transaction_test01
WHERE resi_num = '9203101937988'
AND means IN ('cardOne', 'cardTwo')
AND card_transaction_time >= TO_DATE('2020'||'01', 'yyyymm')
AND card_transaction_time < ADD_MONTHS(TO_DATE('2020'||'01', 'yyyymm'), 1)
)
-- 2. SUM(CASE 를 이용한 피벗 구현으로 테이블 읽기 횟수 줄이기(8회 -> 1회) --
SELECT NVL(SUM(CASE WHEN cd IN ('I1', 'I2' ) THEN amt END), 0) type1
, NVL(SUM(CASE WHEN cd IN ('I4', 'I5', 'I6') THEN amt END), 0) type2
, NVL(SUM(CASE WHEN cd IN ('I7', 'I8' ) THEN amt END), 0) type3
, NVL(SUM(CASE WHEN cd IN ('I9' ) THEN amt END), 0) type4
, NVL(SUM(CASE WHEN cd IN ('I10' ) THEN amt END), 0) type5
, NVL(SUM(CASE WHEN cd IN ('I11' ) THEN amt END), 0) type6
, NVL(SUM(CASE WHEN cd IN ('I12' ) THEN amt END), 0) type7
, NVL(SUM(CASE WHEN cd IN ('I13' ) THEN amt END), 0) type8
FROM whole
;
-- 3. 2단계 집계로 CASE 함수 사용 횟수 줄이기( 8천만회(천만건*8번) -> 96회(12종*8번) ) --
SELECT NVL(SUM(CASE WHEN cd IN ('I1', 'I2' ) THEN amt END), 0) type1
, NVL(SUM(CASE WHEN cd IN ('I4', 'I5', 'I6') THEN amt END), 0) type2
, NVL(SUM(CASE WHEN cd IN ('I7', 'I8' ) THEN amt END), 0) type3
, NVL(SUM(CASE WHEN cd IN ('I9' ) THEN amt END), 0) type4
, NVL(SUM(CASE WHEN cd IN ('I10' ) THEN amt END), 0) type5
, NVL(SUM(CASE WHEN cd IN ('I11' ) THEN amt END), 0) type6
, NVL(SUM(CASE WHEN cd IN ('I12' ) THEN amt END), 0) type7
, NVL(SUM(CASE WHEN cd IN ('I13' ) THEN amt END), 0) type8
FROM (SELECT cd
, SUM(amt) amt
FROM whole
GROUP BY cd
)
;
와 정말 감사합니다..
기존 코드에서 0.054초 걸렸는데
짜주신 코드로 실행하니 0.005 초로 10배이상 속도가 빨라졌습니다.
세가지 조건을 항상 염두에 두고 SQL 짜도록 하겠습니다.
답변 정말 감사합니다.