-- 인덱스 선두 칼럼 가공 (FBI 예외)
select * from 업체 where substr(업체명, 1, 2) = '대한'
-- 부정형 비교
select * from 고객 where 직업 <> '학생'
-- 부정형 비교
select * from 사원 where 부서코드 is not null
select * from 사원 where 연락처 is null
select * from emp where deptno = '20'
-------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
-------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 273 | 1 |
| 1 | TABLE ACCESS BY INDEX ROWID | EMP | 3 | 273 | 1 |
|* 2 | INDEX RANGE SCAN | EMP_DEPTNO_IDX | 1 | | 1 |
-------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMP"."DEPTNO"=20) → 문자형 상수 '20'이 숫자형 20으로 변환됨
select * from emp where cdeptno = 20
-------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
-------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 273 | 2 |
|* 1 | TABLE ACCESS FULL | EMP | 3 | 273 | 2 |
-------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_NUMBER("EMP"."CDEPTNO")=20) → 문자형 CDEPTNO 칼럼이 숫자형으로 변환됨
SQL> select * from 고객 where 지역 = '서울';
Execution Plan ------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS
1 0 TABLE ACCESS (BY INDEX ROWID) OF '고객' (TABLE)
2 1 INDEX (RANGE SCAN) OF '고객_지역_IDX' (INDEX)
StmtText -------------------------------------------------------------
|--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1000]))
|--Index Seek(OBJECT:([..].[dbo].[고객].[고객_지역_idx]), SEEK:([지역] = '서울')
|--RID Lookup(OBJECT:([..].[dbo].[고객]), SEEK:([Bmk1000]=[Bmk1000]) LOOKUP ORDERED FORWARD)
SQL> select * from 고객 where 지역 = '서울';
Execution Plan
------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS
1 0 TABLE ACCESS (BY INDEX ROWID) OF '고객' (TABLE)
2 1 INDEX (RANGE SCAN) OF '고객_지역_IDX' (INDEX)
select /*+ index(emp emp_x01) */ ename, job, sal from emp where deptno = 30 and sal >= 2000
select ename, job, sal from emp where deptno = 30 and job = 'CLERK'
create index emp_x01 on emp (deptno) include (sal)
where 아파트시세코드 = :a
where 아파트시세코드 = :a and 평형 = :b
where 아파트시세코드 = :a and 평형 = :b and 평형타입 = :c
where 아파트시세코드 = :a and 평형 = :b and 평형타입 between :c and :d
select 해당층, 평당가, 입력일, 해당동, 매물구분, 연사용일수, 중개업소코드
from 매물아파트매매
where 아파트시세코드='A01011350900056' and 평형 = '59'
and 평형타입 = 'A' and 인터넷매물 between '1' and '2'
order by 입력일 desc
select 해당층, 평당가, 입력일, 해당동, 매물구분, 연사용일수, 중개업소코드
from 매물아파트매매
where 인터넷매물 in ('1', '2') and 아파트시세코드='A01011350900056'
and 평형 = '59' and 평형타입 = 'A'
order by 입력일 desc
-------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |
-------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 37 | | 1 | INLIST ITERATOR | | | |
| 2 | TABLE ACCESS BY INDEX ROWID | 매물아파트매매 | 1 | 37 | | 3 | INDEX RANGE SCAN | 매물아파트매매_PK | 1 | | -------------------------------------------------------------
'매물아파트매매' 테이블. 스캔 수 2, 논리적 읽기 수 8, 물리적 읽기 수 0, 미리 읽기 수 0.
Rows StmtText
----- --------------------------------------------------------
2 SELECT 해당층, 평당가, 입력일, 해당동, 매물구분, 연사용일수, 중개업소코드, ...
2 |--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1000]))
2 |--Index Seek(OBJECT:([..].[dbo].[매물아파트매매].[매물아파트매매_PK]),
| SEEK:([매물아파트매매].[인터넷매물]='1' AND
| [매물아파트매매].[아파트시세코드]='A01011350900056'AND
| [매물아파트매매].[평형]='59' AND
| [매물아파트매매].[평형타입]='A' OR
| [매물아파트매매].[인터넷매물]='2' AND
| [매물아파트매매].[아파트시세코드]='A01011350900056' AND
| [매물아파트매매].[평형]='59' AND
| [매물아파트매매].[평형타입]='A')
2 |--RID Lookup(OBJECT:([SQLPRO].[dbo].[매물아파트매매]) , SEEK:([Bmk1000]=[Bmk1000]))
select 해당층, 평당가, 입력일, 해당동, 매물구분, 연사용일수, 중개업소코드
from 매물아파트매매
where 인터넷매물 = '1'
and 아파트시세코드='A01011350900056'
and 평형 = '59'
and 평형타입 = 'A'
union all
select 해당층, 평당가, 입력일, 해당동, 매물구분, 연사용일수, 중개업소코드
from 매물아파트매매
where 인터넷매물 = '2'
and 아파트시세코드='A01011350900056'
and 평형 = '59'
and 평형타입 = 'A'
order by 입력일 desc
-- 범위검색 조건을 두개 이상 사용하면, 둘중 하나만 인덱스 스캔 범위를 결정하고 나머지는 필터 조건 역할 수행 (성능상 불리)
select 고객ID, 상품명, 지역, ...
from 가입상품
where 회사 = :com
and 지역 like :reg || '%'
and 상품명 like :prod || '%'
-- 지역 컬럼 검색 조건이 선택적 일 경우 대안1
< SQL1 >
select 고객ID, 상품명, 지역, ...
from 가입상품
where 회사 = :com
and 상품명 like :prod || '%'
< SQL2 >
select 고객ID, 상품명, 지역, ...
from 가입상품
where 회사 = :com
and 지역 = :reg
and 상품명 like :prod || '%'
-- 지역 컬럼 검색 조건이 선택적 일 경우 대안2 (하단 SQL 은 효율적 동작, 상단 SQL 효율을 위해서 인덱스\[회사 + 상품명\] 필요)
select 고객ID, 상품명, 지역, ...
from 가입상품
where :reg is null
and 회사 = :com
and 상품명 like :prod || '%'
union all
select 고객ID, 상품명, 지역, ...
from 가입상품
where :reg is not null
and 회사 = :com
and 지역 = :reg
and 상품명 like :prod || '%'
인덱스 설게
인덱스 설계는 공식이 아닌 전략과 선택의 문제.
\ |