[사례연구 #08] Sub-query로 Join해결
* Join과 Sub-query를 성능상 비교 대상이 될 수 있다.
기본적으로 테이블에 대한 데이터 처리를 join에서 할 때와 sub-query
에서 할 때를 서로 비교함으로써 상대적으로 적게 데이터를 처리할 수
있도록 하는 방법을 선택할 수 있어야 한다.
- Correlated Sub-query와 Nested Sub-query 사용을 통해서 조인에
대한 튜닝을 하고자 함.
에서 할 때를 서로 비교함으로써 상대적으로 적게 데이터를 처리할 수
있도록 하는 방법을 선택할 수 있어야 한다.
- Correlated Sub-query와 Nested Sub-query 사용을 통해서 조인에
대한 튜닝을 하고자 함.
① Correlated sub-query의 실행원리
항상 main-query가 먼저 실행되며, 이때 데이터가 추출되는 가운데
sub-query가 반복해서 실행된다.
② Nested sub-query의 실행원리
일반적으로 sub-query가 먼저 실행되며, 그 후에 main-query가
실행된다.
항상 main-query가 먼저 실행되며, 이때 데이터가 추출되는 가운데
sub-query가 반복해서 실행된다.
② Nested sub-query의 실행원리
일반적으로 sub-query가 먼저 실행되며, 그 후에 main-query가
실행된다.
㈜ Sub-query의 수행결과에 비교되는 Main-query컬럼에
인덱스가 없으면 먼저 수행되지 않는다.
인덱스가 없으면 먼저 수행되지 않는다.
또한 Correlated Sub_query와 함께 OR조건에 의해서
사용되고 있다면 먼저 수행되지 않는다.
사용되고 있다면 먼저 수행되지 않는다.
→ WHERE (Nested Subquery) OR (Correlated Subquery)
* 모든 Subquery가 메인쿼리보다 나중에 행된다!!!
[사례연구 #09] Scalar 서브쿼리 활용
* Join을 튜닝할 때 사용할 수 있는 방법으로써, User Defined Function과
Scalar subquery를 서로 비교함.
Scalar subquery를 서로 비교함.
이 때 테이블에 대한 데이터 처리를 join에서 할 때와 두 방법에서
할 때를 서로 비교함으로써 상대적으로 데이터를 적게 처리할 수
있도록 하는 방법을 선택할 수 있어야 한다.
할 때를 서로 비교함으로써 상대적으로 데이터를 적게 처리할 수
있도록 하는 방법을 선택할 수 있어야 한다.
* UDF와 Scalar subquery의 특성
① 이들은 두 건 이상의 데이터를 한 번에 return할 수 없다.
② 찾고자 하는 데이터가 없는 경우엔 NULL을 return한다.
③ 이들은 마치 loop를 수행하는 것과 같이 SQL을 실행하게 된다.
특히, 이 부분을 주의해야 함.
② 찾고자 하는 데이터가 없는 경우엔 NULL을 return한다.
③ 이들은 마치 loop를 수행하는 것과 같이 SQL을 실행하게 된다.
특히, 이 부분을 주의해야 함.
→ UDF 사용 보다는 Scalar subquery에 의한 퍼포먼스가 더 좋다.
Part 4. Analytic Functions 활용
분석함수(Analytic Functions)는 복잡한 business logic을 구현하고,
대용량 데이터를 효율적으로 처리할 수 있게 하는 함수이다.
대용량 데이터를 효율적으로 처리할 수 있게 하는 함수이다.
이러한 함수는 대부분의 Self join 과 Self subquery 형태의 SQL을
튜닝하는 차원에서 활용할 수 있는 수단이 될 수 있다.
튜닝하는 차원에서 활용할 수 있는 수단이 될 수 있다.
따라서 Part 4 에서는 주어진 사례를 통해서 분석함수 활용 방안
에 대해서 알아보고자 한다.
에 대해서 알아보고자 한다.
[사례연구 #10] Self-조인 해결Ⅰ
* Analytic functions 사용을 통해서 기존의 self-join을 제거할 수
있도록 한다. 이러한 함수는 self-subquery를 제거하는 차원에서도
사용할 수 있다. (Analytic functions은 v8i 부터 사용 가능)
있도록 한다. 이러한 함수는 self-subquery를 제거하는 차원에서도
사용할 수 있다. (Analytic functions은 v8i 부터 사용 가능)
* GROUP함수 KEEP( )
SELECT BRNCOD,CMPID,
MAX(STSDAT) KEEP(DENSE_RANK FIRST ORDER BY STSDAT DESC, STS DESC),
MAX(STS) KEEP(DENSE_RANK FIRST ORDER BY STSDAT DESC, STS DESC),
MAX(AMT) KEEP(DENSE_RANK FIRST ORDER BY STSDAT DESC, STS DESC)
FROM CUSTOMER
WHERE STSDAT <= '20031130'
GROUP BY BRNCOD, CMPID;
MAX(STSDAT) KEEP(DENSE_RANK FIRST ORDER BY STSDAT DESC, STS DESC),
MAX(STS) KEEP(DENSE_RANK FIRST ORDER BY STSDAT DESC, STS DESC),
MAX(AMT) KEEP(DENSE_RANK FIRST ORDER BY STSDAT DESC, STS DESC)
FROM CUSTOMER
WHERE STSDAT <= '20031130'
GROUP BY BRNCOD, CMPID;
SELECT BRNCOD,CMPID,
MAX(STSDAT) KEEP(DENSE_RANK LAST ORDER BY STSDAT ASC, STS ASC),
MAX(STS) KEEP(DENSE_RANK LAST ORDER BY STSDAT ASC, STS ASC),
MAX(AMT) KEEP(DENSE_RANK LAST ORDER BY STSDAT ASC, STS ASC)
FROM CUSTOMER
WHERE STSDAT <= '20031130'
GROUP BY BRNCOD, CMPID;
본 예제의 경우 다음과 같은 analytic functions를 사용하였다.
1) FIRST_VALUE(expr) OVER([PARTITION BY][ORDER BY][WINDOWING절])
2) LAST_VALUE(expr) OVER([PARTITION BY][ORDER BY][WINDOWING절])
3) MAX(expr) OVER([PARTITION BY][ORDER BY][WINDOWING절])
2) LAST_VALUE(expr) OVER([PARTITION BY][ORDER BY][WINDOWING절])
3) MAX(expr) OVER([PARTITION BY][ORDER BY][WINDOWING절])
* MAX(...) OVER(...) 함수 사용에 의한 SQL - 추가 작성
SELECT C.BRNCOD, C.CMPID, C.STSDAT, C.STS, C.AMT
FROM (SELECT BRNCOD, CMPID, STSDAT, STS,
MAX(STSDAT||STS)
OVER(PARTITION BY BRNCOD, CMPID
ORDER BY STSDAT DESC, STS DESC
ROWS UNBOUNDED PRECEDING) MAX_DTSTS,
AMT
FROM CUSTOMER
WHERE STSDAT <= '20031130') C
WHERE C.STSDAT = SUBSTR(C.MAX_DTSTS,1,8)
AND C.STS = SUBSTR(C.MAX_DTSTS,9,1)
AND C.AMT > 0;
FROM (SELECT BRNCOD, CMPID, STSDAT, STS,
MAX(STSDAT||STS)
OVER(PARTITION BY BRNCOD, CMPID
ORDER BY STSDAT DESC, STS DESC
ROWS UNBOUNDED PRECEDING) MAX_DTSTS,
AMT
FROM CUSTOMER
WHERE STSDAT <= '20031130') C
WHERE C.STSDAT = SUBSTR(C.MAX_DTSTS,1,8)
AND C.STS = SUBSTR(C.MAX_DTSTS,9,1)
AND C.AMT > 0;
SELECT C.BRNCOD, C.CMPID, C.STSDAT, C.STS, C.AMT
FROM (SELECT BRNCOD, CMPID, STSDAT, STS,
MAX(STSDAT||STS)
OVER(PARTITION BY BRNCOD, CMPID
ORDER BY STSDAT ASC, STS ASC
ROWS BETWEEN CURRENT ROW
AND UNBOUNDED FOLLOWING) MAX_DTSTS,
AMT
FROM CUSTOMER
WHERE STSDAT <= '20031130') C
WHERE C.STSDAT = SUBSTR(C.MAX_DTSTS,1,8)
AND C.STS = SUBSTR(C.MAX_DTSTS,9,1)
AND C.AMT > 0;
[사례연구 #11] Self-조인 해결Ⅱ
* [사례연구 #10]과 마찬가지로 self-join 제거를 위해 사용할 수 있는
Analytic Function에 대해서 학습
※ 본 예제의 경우 아래의 analytic function를 사용하였다.
1) LEAD(expr) OVER([PARTITION BY][ORDER BY])
~ 각 데이터를 기준으로 바로 그 다음 데이터를 처리토록 함
㈜ Windowing절을 갖지 않는다.
2) LAG(expr) OVER([PARTITION BY][ORDER BY])
~ 각 데이터를 기준으로 바로 앞의 데이터를 처리토록 함
㈜ Windowing절을 갖지 않는다.
eg) 직전 가격처리 예제
㈜ Windowing절을 갖지 않는다.
2) LAG(expr) OVER([PARTITION BY][ORDER BY])
~ 각 데이터를 기준으로 바로 앞의 데이터를 처리토록 함
㈜ Windowing절을 갖지 않는다.
eg) 직전 가격처리 예제
SELECT CODE, SEQ_NO, PRICE AS CUR_PRI,
LAG(PRICE,1,0) OVER(PARTITION BY CODE
ORDER BY SEQ_NO ASC) AS BEF_PRI
FROM DANGA_HIST;
LAG(PRICE,1,0) OVER(PARTITION BY CODE
ORDER BY SEQ_NO ASC) AS BEF_PRI
FROM DANGA_HIST;
* Outer 조인과 같은 결과를 낳는 U.D.F(User Defined Function) 사용
=============================
→ 종료일을 처리하기 위한 차원에서 User Defined Function 사용
CREATE OR REPLACE FUNCTION FN_ENDYMD(A_CD IN VARCHAR2, A_SQ IN VARCHAR2)
RETURN VARCHAR2
IS
H_END_YMD DANGA_HIST.BEGIN_YMD%TYPE := NULL;
BEGIN
RETURN VARCHAR2
IS
H_END_YMD DANGA_HIST.BEGIN_YMD%TYPE := NULL;
BEGIN
SELECT BEGIN_YMD INTO H_END_YMD
FROM DANGA_HIST
WHERE CODE = A_CD
AND SEQ_NO = A_SQ + 1;
FROM DANGA_HIST
WHERE CODE = A_CD
AND SEQ_NO = A_SQ + 1;
RETURN H_END_YMD;
END;
/
END;
/
----------------------------------------------------------
→ SELECT CODE, SEQ_NO, PRICE, BEGIN_YMD,
NVL(FN_ENDYMD(CODE, SEQ_NO),'99991231') AS END_YMD
FROM DANGA_HIST
ORDER BY CODE ASC, SEQ_NO ASC;
----------------------------------------------------------
→ SELECT CODE, SEQ_NO, PRICE, BEGIN_YMD,
NVL(FN_ENDYMD(CODE, SEQ_NO),'99991231') AS END_YMD
FROM DANGA_HIST
ORDER BY CODE ASC, SEQ_NO ASC;
----------------------------------------------------------
Part 5. Cartesian Product
Cartesian Product는 다음과 같은 조인을 수행할 때 발생한다.
① WHERE절 없는 조인 수행
② 조인을 위한 조건 없이 조인 수행
① WHERE절 없는 조인 수행
② 조인을 위한 조건 없이 조인 수행
Cartesian Product는 "데이터 복제" 라는 개념을 활용하기 위해 사용하게
된다. 그 러나 잘못 사용하는 경우에는 오히려 데이터를 부풀리는 원인이
되기 때문에 퍼포먼스를 오히려 나쁘게 할 수도 있다.
된다. 그 러나 잘못 사용하는 경우에는 오히려 데이터를 부풀리는 원인이
되기 때문에 퍼포먼스를 오히려 나쁘게 할 수도 있다.
Part 5 에서는 Cartesian Product를 적용해야 할 대상을 사례별로 다루어
봄으로써, Cartesian Product를 정확하게 사용할 수 있도록 하고자 한다.
봄으로써, Cartesian Product를 정확하게 사용할 수 있도록 하고자 한다.
참고) Cartesian Product에 의한 '2011'년 날짜 생성
SELECT YMD
FROM (SELECT '2011'||B.DAY||A.DAY AS YMD,
TO_CHAR(LAST_DAY(TO_DATE('2011'||B.DAY,'YYYYMM'))
,'YYYYMMDD') AS L_DAY, ROWNUM
FROM EC_DAY A, EC_DAY B
WHERE B.DAY <= '12')
WHERE YMD <= L_DAY;
FROM (SELECT '2011'||B.DAY||A.DAY AS YMD,
TO_CHAR(LAST_DAY(TO_DATE('2011'||B.DAY,'YYYYMM'))
,'YYYYMMDD') AS L_DAY, ROWNUM
FROM EC_DAY A, EC_DAY B
WHERE B.DAY <= '12')
WHERE YMD <= L_DAY;
'04번. IT 힌트얻기 > ▶ DB Tuning' 카테고리의 다른 글
[튜닝알아가기] 첫번째 이야기 (0) | 2011.10.18 |
---|---|
[Tuning] perfect_study_04 (0) | 2011.10.14 |
[Tuning] perfect_study_02 (0) | 2011.10.12 |
[Tuning] 분석함수의 활용 (셀프조인의 해결) (0) | 2011.10.12 |
[Tuning] 분석함수의 활용 (셀프조인의 해결) (0) | 2011.10.12 |