오라클 9i 입니다.
토드에서 아래와 같이 1번쿼리와 2번쿼리 경우 속도에서 차이가 납니다. (1번쿼리는 바로조회되는데., 2번쿼리는 1분이 넘어도 조회가 안되네요...)
1번과 2번의 차이가 where 절차이( 아규먼트 or 직접명기) 차이밖에 없거든요..
이게 정상인건가요?
1번+++++++++++++++++++++++++++++++++++++++++++++++++++++
SELECT YY ,
MM,
HOGI ,
SUM(SL_WGT) ,
SUM(TOT_WGT) ,
ROUND(SUM(SL_WGT) / SUM(TOT_WGT) * 100 ,2) YUL
FROM
(
SELECT TO_CHAR(IB_ILJA ,'YYYY') AS YY ,
TO_CHAR(IB_ILJA ,'MM' ) AS MM ,
HOGI ,
0 SL_WGT,
SUM(MC_WGT) TOT_WGT
FROM SMDHP.SM_MCD A
WHERE IB_ILJA BETWEEN '20170101' AND '20170930'
GROUP BY TO_CHAR(IB_ILJA ,'YYYY'),TO_CHAR(IB_ILJA ,'MM') ,HOGI
UNION ALL
SELECT TO_CHAR(IB_ILJA ,'YYYY') AS YY ,
TO_CHAR(IB_ILJA ,'MM' ) AS MM ,
HOGI ,
0 SL_WGT,
SUM(MC_WGT) TOT_WGT
FROM SMDHP.SM_MCD A
WHERE IB_ILJA BETWEEN '20160101' AND '20160930'
GROUP BY TO_CHAR(IB_ILJA ,'YYYY'),TO_CHAR(IB_ILJA ,'MM') ,HOGI
)
WHERE HOGI = '1'
GROUP BY YY, MM, HOGI
ORDER BY HOGI, YY DESC , MM
1번쿼리 실행계획 +++++++++++++++++++++++++++++++++++++++++++++++++++++
Operation Object Name Rows Bytes Cost Object Node In/Out PStart PStop
SELECT STATEMENT Optimizer Mode=CHOOSE 2 11
SORT GROUP BY 2 48 11
VIEW 2 48 10
UNION-ALL
SORT GROUP BY 1 15 5
FILTER
TABLE ACCESS BY INDEX ROWID SMDHP.SM_MCD 222 3 K 3
INDEX RANGE SCAN SMDHP.IDX_SM_MCD02 887 2
SORT GROUP BY 1 15 5
FILTER
TABLE ACCESS BY INDEX ROWID SMDHP.SM_MCD 222 3 K 3
INDEX RANGE SCAN SMDHP.IDX_SM_MCD02 887 2
2번. +++++++++++++++++++++++++++++++++++++++++++++++++++++
where 절을 .. 아래와같이 변수(아규먼트) 로 조회 할 경우.
A.IB_ILJA BETWEEN TO_DATE(:AG_YYMM1||'01','RRRRMMDD') AND LAST_DAY(TO_DATE(:AG_YYMM2||'01','RRRRMMDD'))
SELECT YY ,
MM,
HOGI ,
SUM(SL_WGT) ,
SUM(TOT_WGT) ,
ROUND(SUM(SL_WGT) / SUM(TOT_WGT) * 100 ,2) YUL
FROM
(
SELECT TO_CHAR(IB_ILJA ,'YYYY') AS YY ,
TO_CHAR(IB_ILJA ,'MM' ) AS MM ,
HOGI ,
0 SL_WGT,
SUM(MC_WGT) TOT_WGT
FROM SMDHP.SM_MCD A
WHERE IB_ILJA BETWEEN TO_DATE(:AG_YYMM1||'01','RRRRMMDD') AND LAST_DAY(TO_DATE(:AG_YYMM2||'01','RRRRMMDD'))
GROUP BY TO_CHAR(IB_ILJA ,'YYYY'),TO_CHAR(IB_ILJA ,'MM') ,HOGI
UNION ALL
SELECT TO_CHAR(IB_ILJA ,'YYYY') AS YY ,
TO_CHAR(IB_ILJA ,'MM' ) AS MM ,
HOGI ,
0 SL_WGT,
SUM(MC_WGT) TOT_WGT
FROM SMDHP.SM_MCD A
WHERE IB_ILJA BETWEEN ADD_MONTHS(TO_DATE(:AG_YYMM1||'01','RRRRMMDD'),-12) AND
LAST_DAY(ADD_MONTHS(TO_DATE(:AG_YYMM2|| '01','RRRR-MM-DD'),-12))
GROUP BY TO_CHAR(IB_ILJA ,'YYYY'),TO_CHAR(IB_ILJA ,'MM') ,HOGI
)
WHERE HOGI = '1'
GROUP BY YY, MM, HOGI
ORDER BY HOGI, YY DESC , MM
2번쿼리 실행계획 +++++++++++++++++++++++++++++++++++++++++++++++++++++
Operation Object Name Rows Bytes Cost Object Node In/Out PStart PStop
SELECT STATEMENT Optimizer Mode=CHOOSE 1 K 433
SORT GROUP BY 1 K 31 K 433
VIEW 1 K 31 K 428
UNION-ALL
SORT GROUP BY 671 9 K 214
FILTER
TABLE ACCESS BY INDEX ROWID SMDHP.SM_MCD 1 K 18 K 208
INDEX RANGE SCAN SMDHP.IDX_SM_MCD03 493 K 8
SORT GROUP BY 671 9 K 214
FILTER
TABLE ACCESS BY INDEX ROWID SMDHP.SM_MCD 1 K 18 K 208
INDEX RANGE SCAN SMDHP.IDX_SM_MCD03 493 K 8
그렇군요
1번 SQL : INDEX RANGE SCAN SMDHP.IDX_SM_MCD02 인덱스칼럼 : ib_ilja , hogi, lot
2번 SQL : INDEX RANGE SCAN SMDHP.IDX_SM_MCD03 인덱스칼럼 : hogi, lot
이렇게되어 있는데...
WHERE IB_ILJA BETWEEN TO_DATE(:AG_YYMM1||'01','RRRRMMDD') AND LAST_DAY(TO_DATE(:AG_YYMM2||'01','RRRRMMDD')) 이걸썻을경우.... ib_ilja 포함 인덱스를 못타는거 같은데요...
이게 정상인가요? 제가 알기론 where 절에 ib_ilja 에 변형을 가하지 않으면 인덱스 타는거 아니던가요?
예를들면 where to_char(ib_ilja ,'yyyymm') ...
이런식으로 변형을 가하면 인덱스를 못탄다고 알고 있습니다만... 예시의경우는 타야되는거 아닐까요? .
1번 쿼리는 문자열 조건을 주었고 / 2번 쿼리는 날짜형 조건을 주었네요.
1번 쿼리가 빨랐다면? 해당 컬럼이 문자형인 듯 하네요.
2번 쿼리의 조건을 to_char 를 이용해 문자열로 바꾸셔야 합니다.
그거 이외에도 문제가 많습니다.
1. group by 이후에 호기 조건을 주는데
- group by 하기 전에 조건을 주는게 좋습니다.
2. 두가지 union sum 이 있는데. 두개 쿼리의 sum 의 위치가 서로 같네요?
- 전년도와 당해년도 sum 의 위치가 달라야 맞을 듯 하네요.
3. union 으로 두번 쿼리하는데
- or 절로 한번에 쿼리하여
- select 절에서 sum(case 로 두가지 sum 을 구하시는게 좋을 듯.
IB_ILJA 가 문자형 컬럼이죠? 문자형 컬럼이라고 할 때
IB_ILJA BETWEEN TO_DATE(:AG_YYMM1||'01','RRRRMMDD') AND LAST_DAY(TO_DATE(:AG_YYMM2||'01','RRRRMMDD'))
위와 같이 문자형 컬럼과 일자형 컬럼을 비교하시면
날짜형이 우선순위가 더 높아 묵시적으로 형변환이 일어납니다.
내부적으로는
TO_DATE(IB_ILJA,'RRRRMMDD') BETWEEN TO_DATE(:AG_YYMM1||'01','RRRRMMDD') AND LAST_DAY(TO_DATE(:AG_YYMM2||'01','RRRRMMDD'))
이렇게 바뀝니다. 묵시적 형변환으로 인덱스 사용 못 합니다.
date 타입이 확실하구요...제가 테스트 해보니까 hogi 조건이 있느냐 없느냐에 따라서 달라집니다.
위에 부쉬멘님께도 말씀드렷지만
1번 SQL : INDEX RANGE SCAN SMDHP.IDX_SM_MCD02 인덱스칼럼 : ib_ilja , hogi, lot
2번 SQL : INDEX RANGE SCAN SMDHP.IDX_SM_MCD03 인덱스칼럼 : hogi, lot
인덱스가 이렇게 구성되어 있는데요...호기 조건이들어가면 2번 인덱스 타면서 느려집니다. ㅡㅡ
문제가 좀 복합적인거 같아요... 1번쿼리는 호기 조건을 넣어도...1번 인덱스르 탑니다.
모두 모든분들 답변 감사드립니다.
1. 우선 힌트로 해결했습니다.
2. 해당칼럼이 DATE 였고 : SMDHP.IDX_SM_MCD02 (인덱스칼럼 : ib_ilja , hogi, lot )
: SMDHP.IDX_SM_MCD03 (인덱스칼럼 : hogi, lot ) <---- 요놈이 몇개월전(?)에 추가한 문제의 새로운 인덱스였습니다.
3. 날짜칼럼에 데이타는 '2017-01-01' 타입으로 시간제외하고 들어가 있습니다.
HOGI 조건이 밖에 있던 것, UNION ALL 항목 교차되지 않고 같은위치에 중첩되는것은 쿼리 단순화 하면서 잘못적용한 단순 실수입니다.... (마농님 질문에 핑계.)
4. 현재) 제가 조회를 막 많이 해봐서 통계가 바뀌었는지 모르겠지만... ㅡㅡ
1) WHERE IB_ILJA BETWEEN '20160101' AND '20160930' +++++ > IDX_SM_MCD02 인덱스 탑니다.
2) WHERE IB_ILJA BETWEEN '2016-01-01' AND '2016-09-30' +++++ > IDX_SM_MCD02 인덱스 탑니다.
2) WHERE IB_ILJA BETWEEN TO_DATE(:AG_YYMM1||'01','RRRRMMDD') AND LAST_DAY(TO_DATE(:AG_YYMM2||'01','RRRRMMDD')) ++++++> IDX_SM_MCD02 인덱스 탑니다.
5. 그러나 WHERE 절에 HOGI = '1' 이라는 조건을 추가하면 .....
1. WHERE IB_ILJA BETWEEN '20160101' AND '20160930' AND HOGI ='1'
-> IDX_SM_MCD02 인덱스 탑니다.
2. WHERE IB_ILJA BETWEEN TO_DATE(:AG_YYMM1||'01','RRRRMMDD') AND LAST_DAY(TO_DATE(:AG_YYMM2||'01','RRRRMMDD')) AND HOGI ='1'
-> IDX_SM_MCD03 인덱스 탑니다.
이런상황이네요~~
여기만 매달릴수 없어서 일단 힌트치고..다른일좀 ^^
모두 감사드려요.