select 거래일자, 종목코드, 투자자유형코드, 주문매체코드
, 체결건수, 체결수량, 거래대금
from 일별종목거래
where 거래일자 between :시작일자 and :종료일자
%option
%option = " and 종목코드 = 'KR123456' and 투자자유형코드 = '1000'"
select 거래일자, 종목코드, 투자자유형코드, 주문매체코드
, 체결건수, 체결수량, 거래대금
from 일별종목거래
where 거래일자 between :시작일자 and :종료일자
and 종목코드 = nvl(:종목코드, 종목코드)
and 투자자유형코드 = nvl(:투자자유형코드, 투자자유형코드)
and 주문매체구분코드 = nvl(:주문매체구분코드, 주문매체구분코드)
1. 거래일자 between
2. 거래일자 between, 종목코드 =
3. 거래일자 between, 종목코드 =, 투자자유형코드 =
4. 거래일자 between, 종목코드 =, 투자자유형코드 =, 주문매체구분코드 =
5. 거래일자 between, 종목코드 =, 주문매체구분코드 =
6. 거래일자 between, 투자자유형코드 =
7. 거래일자 between, 투자자유형코드 =, 주문매체구분코드 =
8. 거래일자 between, 주문매체구분코드 =
< 인덱스 구성 >
INDEX01 : 종목코드 + 거래일자
INDEX02 : 투자자유형코드 + 거래일자 + 주문매체구분코드
INDEX03 : 거래일자 + 주문매체구분코드
select 거래일자, 투자자유형코드, 회원번호
, 체결건수, 체결수량, 거래대금
from 일별종목거래
where :종목코드 is not null
and 거래일자 between :시작일자 and :종료일자
and 종목코드 = :종목코드
and 투자자유형코드 = nvl(:투자자유형, 투자자유형코드)
and 주문매체구분코드 = nvl(:주문매체, 주문매체코드)
union all
select 거래일자, 투자자유형코드, 회원번호
, 체결건수, 체결수량, 거래대금
from 일별종목거래
where :종목코드 is null and : 투자자유형 is not null
and 거래일자 between :시작일자 and :종료일자
and 투자자유형코드 = nvl(:투자자유형, 투자자유형코드)
and 주문매체구분코드 = nvl(:주문매체, 주문매체코드
union all
select 거래일자, 투자자유형코드, 회원번호
, 체결건수, 체결수량, 거래대금
from 일별종목거래
where :종목코드 is null and :투자자유형 is null
and 거래일자 between :시작일자 and :종료일자
and 주문매체구분코드 = nvl(:주문매체, 주문매체구분코드)
SQLStmt := 'SELECT 거래일자, 종목코드, 투자자유형코드, '
|| '주문매체코드, 체결건수, 체결수량, 거래대금 '
|| 'FROM 일별종목거래 '
|| 'WHERE 거래일자 BETWEEN :1 AND :2 ';
IF :종목코드 IS NULL Then
SQLStmt := SQLStmt || 'AND :3 IS NULL ';
Else
SQLStmt := SQLStmt || 'AND 종목코드 = :3 ';
End If;
If :투자자유형 IS NULL Then
SQLStmt := SQLStmt || 'AND :4 IS NULL ';
Else
SQLStmt := SQLStmt || 'AND 투자자유형코드 =:4 ';
End If;
EXECUTE IMMEDIATE SQLStmt
INTO :A, :B, :C, :D, :E, :F, :G
USING :시작일자, :종료일자, :종목코드, :투자자유형코드;
SELECT 거래일자, 종목코드, 투자자유형코드, 주문매체코드
, 체결건수, 체결수량, 거래대금
FROM 일별종목거래
WHERE 거래일자 BETWEEN ? AND ?
SELECT 거래일자, 종목코드, 투자자유형코드, 주문매체코드
, 체결건수, 체결수량, 거래대금
FROM 일별종목거래
WHERE 거래일자 BETWEEN ? AND ?
AND 종목코드 = ?
SELECT 거래일자, 종목코드, 투자자유형코드, 주문매체코드
, 체결건수, 체결수량, 거래대금
FROM 일별종목거래
WHERE 거래일자 BETWEEN ? AND ?
AND 투자자우형코드 = ?
SELECT 거래일자, 종목코드, 투자자유형코드, 주문매체코드
, 체결건수, 체결수량, 거래대금
FROM 일별종목거래
WHERE 거래일자 BETWEEN ? AND ?
AND 종목코드 = ?
AND 투자자유형코드 = ?
select * from 일별종목거래 where (:isu_cd is null or isu_cd = :siu_cd) Execution Plan --------------------------------------------------- 0 SELECT STATEMENT Optimizer=ALL_ROWS 1 0 TABLE ACCESS (FULL) OF '일별종목거래' (TABLE)
- 항상 Table Full Scan으로 처리되므로 인덱스 활용이 필요할 때는 이 방식을 사용해선 안 됩니다.
select * from 일별종목거래 where isu_cd like :isu_cd || '%' Execution Plan --------------------------------------------------- 0 SELECT STATEMENT Optimizer=ALL_ROWS 1 0 TABLE ACCESS (BY LOCAL INDEX ROWID) OF '일별종목거래' (TABLE) 2 1 INDEX (RANGE SCAN) OF '일별 종목거래_PK' (INDEX (UNIQUE))
- 인덱스 사용이 가능하지만 사용자가 :isu_cd 값을 입력하지 않았을 때 Table Full Scan이 유리한데도 인덱스를 사용하게 되므로 성능이 나빠질 수 있습니다.
select * from 일별종목거래 where isu_cd = nvl(:isu_cd, isu_cd) Execution Plan --------------------------------------------------- 0 SELECT STATEMENT Optimizer=ALL_ROWS 1 0 CONCATENATION 2 1 FILTER 3 2 TABLE ACCESS (FULL) OF '일별종목거래' (TABLE) 4 1 FILTER 5 4 TABLE ACCCESS (BY LOCAL INDEX ROWID) OF '일별종목거래' (TABLE) 6 5 INDEX (RANGE SCAN) OF '일별종목거래_PK' (INDEX (UNIQUE))
select * from 일별종목거래 where isu_cd = decode(:isu_cd, null, isu_cd, :isu_cd) Execution Plan --------------------------------------------------- 0 SELECT STATEMENT Optimizer=ALL_ROWS 1 0 CONCATENATION 2 1 FILTER 3 2 TABLE ACCESS (FULL) OF '일별종목거래' (TABLE) 4 1 FILTER 5 4 TABLE ACCESS (BY LOCAL INDEX ROWID) OF '일별종목거래' (TABLE) 6 5 INDEX (RANGE SCAN) OF '일별종목거래_PK' (INDEX (UNIQUE))
- C와 D 방식은, 사용자의 :isu_cd 입력 여부에 따라 Full Table Scan과 Index Scan으로 실행계획이 자동 분기 됩니다. 단, nvl 또는 decode 함수를 사용할 때는 해당 컬럼이 not null 컬럼이어야 하며, null 컬럼이어야 하며, null 허용 컬럼일 때는 결과 집합이 달라지므로 주의해야 합니다. 사용자가 :isu_cd 값을 입력하지 않았을 때는 조건절이 isu_cd = isu_cd가 되는데, isu_cd 컬럼 값이 null일 때 오라클은 false를 리턴하기 때문입니다. 참고로, null = null 비교가 가능한 DBMS도 있기는 합니다. 잘 이해가 되지 않는 다면 아래 결과를 참고하시길.
SQL> select * from dual 2 where NULL = NULL; 선택된 레코드가 없습니다. SQL> select * from dual 2 where NULL IS NULL ; DU -- X 1 개의 행이 선택되었습니다
- nvl 또는 decode를 여러 컬럼에 대해 사용했을 때는 그 중 변별력이 가장 좋은 컬럼 기준으로 한번만 분기가 일어난다는 사실도 기억할 필요가 있고,
복잡한 옵션 조건을 처리 할 때 이 방식에만 의존하기 어려운 이유가 여기에 있습니다.
select * from 일별종목거래 where :isu_cd is null union all select * from 일별종목거래 where :isu_cd is not null and isu_cd = :isu_cd Execution Plan --------------------------------------------------- 0 SELECT STATEMENT Optimizer=ALL_ROWS 1 0 UNION-ALL 2 1 FILTER 3 2 TABLE ACCESS (FULL) OF '일별종목거래' (TABLE) 4 1 FILTER 5 4 TABLE ACCESS (BY LOCAL INDEX ROWID) OF '일별종목거래' (TABLE) 6 5 INDEX (RANGE SCAN) OF '일별종목거래_PK' (INDEX (UNIQUE))
1. not null 컬럼일 때는 nvl, decode를 사용(C와 D)하는 것이 편하다.
2. null 값을 허용하고 인덱스 액세스 조건으로 의미있는 컬럼이라면 union all을 사용(E)해 명시적으로 분기해야한다.
3. 인덱스 액세스 조건으로 참여하지 않는 경우, 즉 인덱스 필터 또는 테이블 필터 조건으로만 사용되는 컬럼이라면 (:c isnull or cao = :c) 또는 (c like :c || '%')어떤 방식을 사용(A와 B) 해도 무방합니다.
이 자료는 (오라클 성능 고도화 원리와해법 I)을 참고 하여 작성했습니다.