SELECT 계약번호, 관리부서명, 계약일, 고객형태, 계약구분, 고객주소
FROM 계약 X, 부서 Y
WHERE Y.부서코드 = X.관리부서
AND 계약번호 LIKE :계약번호 || '%'
AND 관리부서 LIKE :관리부서 || '%'
AND 계약일 LIKE NVL(:기준일, TO_CHAR(SYSDATE,'YYYYMM')||'%'
AND NVL(계약구분,'X') = NVL(:계약구분,'X')
-- 옵티마이져는 입력된 값을 먼저 바인딩하지 않고 변수값 그대로 파싱을 하기 때문에 부여된 값에 따라 실행계획이 달라지지 않는다
-- 즉, 한가지 실행계획만 수립된다
-- 위 SQL의 전제로 계약번호(NULL허용)가 선행컬럼인 결합인덱스가 있다고 했을때 부여한 조건중 계약번호가 NULL인경우는 전체 인덱스를 액세스를 해야하는 최악의 상황
-- 실행계획의 분리로 해결할 수 있다.
SELECT 계약번호, 관리부서명, 계약일, 고객형태, 계약구분, 고객주소
FROM (SELECT *
FROM 계약
WHERE :계약번호 > ' ' // NOT NULL
AND 계약번호 = :계약번호 // 분포도 좋은 계약번호 결합인덱스선행컬럼으로 사용
AND 관리부서 LIKE :관리부서 || '%'
AND 계약일 LIKE NVL(:기준일, TO_CHAR(SYSDATE,'YYYYMM')||'%'
AND NVL(계약구분,'X') = NVL(:계약구분,'X')
UNION ALL
SELECT *
FROM 계약
WHERE :계약번호 IS NULL // NULL 전체범위 처리
AND 관리부서 LIKE :관리부서 || '%'
AND 계약일 LIKE NVL(:기준일, TO_CHAR(SYSDATE,'YYYYMM')||'%'
AND NVL(계약구분,'X') = NVL(:계약구분,'X')
AND ROWNUM <= 300 //처리범위가 너무 넓을때 방호벽으로 사용한다는데 이해가..
) X, 부서 Y WHERE Y.부서코드 = X.부서코드;
-- 처리주관 인덱스의 유형에 따라 UNION ALL로 부류
-- 계약번호컬럼으로 어느 한 집합은 반드시 공집합
-- 공집합이 된 경우는 액세스가 발생되지 않음
-- OR를 이용하여 비슷한 결과를 낼 수도 있으나 비효율적인 실행계획이 수립됨
--- 논리합연산자의 이해-실행계획 분할방법
CREATE INDEX 현행테이블_IND ON 현행테이블(처리일자);
CREATE INDEX 집계테이블_IND ON 집계테이블(집계일자);
SELECT 제품코드, SUM(처리수량)
FROM (SELECT 제품코드, 집계수량 처리수량
FROM 집계테이블
WHERE 집계일자 BETWEEN '20071103' AND '20071203'
UNION ALL
SELECT 제품코드 AS 제품코드, 처리수량 AS 처리수량
FROM 현행테이블
WHERE 처리일자 BETWEEN '20071203' AND '20071204'
)
GROUP BY 제품코드
SELECT STATEMENT
SORT GROUP BY
VIEW
UNION-ALL
TABLE ACCESS BY INDEX ROWID 집계테이블
INDEX RANGE SCAN 집계테이블_IND
TABLE ACCESS BY INDEX ROWID 현행테이블
INDEX RANGE SCAN 현행테이블_IND
--마지막집계일자 구하기
SELECT /*+ INDEX_DESC(A 집계테이블_IND ) */
집계일자
FROM 집계테이블 A
WHERE 집계일자 <= '99991231'
AND ROWNUM = 1
--효율적인 SQL을 위해 뷰를 생성
CREATE VIEW 집계_뷰(발생일자, 제품코드, 수량) AS
SELECT 집계일자, 제품코드, 집계수량
FROM 집계테이블
UNION ALL
SELECT 처리일자, 제품코드, 처리수량
FROM 현행테이블
--뷰를 이용한 쿼리
SELECT *
FROM 집계_뷰
WHERE 발생일자 BETWEEN '20071103' AND '20071203'
SELECT STATEMENT
VIEW 집계_뷰
UNION-ALL
TABLE ACCESS BY INDEX ROWID 집계테이블
INDEX RANGE SCAN 집계테이블_IND
TABLE ACCESS BY INDEX ROWID 현행테이블
INDEX RANGE SCAN 현행테이블_IND
--위 SQL는 아래 SQL과 같은 실행계획을 수립한다.>>
SELECT 집계일자, 제품코드, 집계수량
FROM 집계테이블
WHERE 집계일자 BETWEEN '20071103' AND '20071203'
UNION ALL
SELECT 처리일자, 제품코드, 처리수량
FROM 현행테이블
WHERE 처리일자 BETWEEN '20071103' AND '20071203'
--다른 처리범위를 가질 수 있도록 처리
CREATE OR REPLACE VIEW 집계_뷰(발생일자1, 발생일자2, 제품코드, 수량) AS
SELECT 집계일자, '99999999', 제품코드, 집계수량
FROM 집계테이블
UNION ALL
SELECT 처리일자, 처리일자, 제품코드, 처리수량
FROM 현행테이블
SELECT *
FROM 집계_뷰
WHERE 발생일자1 BETWEEN '20071103' AND '20071203'
AND 발생일자2 >= '20071203'
>>
SELECT 집계일자, 제품코드, 집계수량
FROM 집계테이블
WHERE 집계일자 BETWEEN '20071103' AND '20071203'
AND '99999999' >= '20071203'
UNION ALL
SELECT 처리일자, 제품코드, 처리수량
FROM 현행테이블
WHERE 처리일자 BETWEEN '20071103' AND '20071203'
AND 처리일자 >= '20071203'
--규칙기준 옵티마이져인 경우 동일한 컬럼이 하나이 상의 조건을 가질때 순위의 차이가 있다면 보다 양호한 순위를 가진 조건이 선택되고
--같은 순위를 가진 다면 먼저 사용된 조건을 사용한다
SELECT *
FROM 집계_뷰
WHERE 발생일자2 >= '20071203'
AND 발생일자1 BETWEEN '20071103' AND '20071203'