인덱스에 사용할 컬럼을 선택하고, 순서를 정하는 데는 중요한 기준이 두 가지 있다.
인덱스에 사용할 컬럼을 선택하고
{+}간단한 설계 예제{+}
<검색조건1>
where 고객번호 = 1
and 거래일자 between '20090101'and '20090331'
<검색조건2>
where 상품번호 = 'A'
and 거래일자 between '20090101'and '20090331'
<검색조건3>
where 고객번호 = 1
and 상품번호 = 'A'
and 거래일자 between '20090101'and '20090331'
<검색조건4>
where 거래일자 between '20090101'and '20090331'
{+}효율성 비교분석{+}
스타일A | 스타일I |
---|---|
X1:고객번호+거래일자 X2:상품번호+거래일자 X3:상품번호+고객번호+거래일자 X4:거래일자 | X1:고객번호+거래일자 X2:거래일자+상품번호+고객번호 |
조건 | 스타일A | 스타일I | 비고 |
---|---|---|---|
조건1 | X1 | X1 | 두번의 테이블 Random Access |
조건2 | X2 | X2-불필요한 상품번호까지 스캔하는 비효율존재 | 세번의 테이블 Random Access |
조건3 | X3-단 한건의 Random Access | X1-두번의 테이블액세스, 거래범위가 좁으면 X2를 이용해 불필요한 Random Access를 없애는게 좋을수도 | |
조건4 | X4 | X2 | 동일한 테이블 Random Access, Range파티션 고려 |
{+}스캔 효율성 이외의 판단 기준{+}
{+}인덱스 설계는 공식이 아닌 전략과 선택의 문제{+}
{+}인덱스 전략 수립을 위한 훈련{+}
<쿼리1> - 사용빈도 높음
select * from 고객
where 고객번호 = :no;
<쿼리2>
select * from 고객
where 연령 = :age
and 성별 = :gender
and 이름 like :name || '%';
<쿼리3>
select * from 고객
where 연령 between :age1 and :age2
and 거주지역 = :region
and 등록일 like :rdate || '%';
<쿼리4> - 사용빈도 높음
select /*+ orderd use_nl(b) */ * from 주문 a, 고객 b
where a.거래일자 = :tdate
and a.상품번호 = :good
and a.고객번호 = b.고객번호
and b.거주지역 = :region;
IX01: 고객번호+거주지역(쿼리1, 쿼리4)
IX02: 연령+거주지역(쿼리2, 쿼리3)
{+}선택도가 액세스 효율에 영향을 주지 않는 경우{+}
IDX01 : 고객등급 + 고객번호 + 거래일자 + 거래유형 + 상품번호 |
항상 '=' 조건으로 사용하는 컬럼 : 고객등급, 고객번호(고객등급은 선택도가 높고, 고객번호는 선택도가 낮다.)
between으로 사용하는 컬럼 : 거래일자
{+}선택도가 '높은 컬럼'을 앞쪽에 두는 것이 유리한 경우{+}
{+}상황에 따라 유,불리가 바뀌는 경우{+}
{+}선택도가 '낮은 컬럼'을 앞쪽에 두는 것이 유리한 경우{+}
where 고객번호 = :a and 상품번호 = :b and 거래일자 between :c and :d |
=>최선의 인덱스 설계는 고객번호+상품번호+거래일자
{+}선택도가 낮은 컬럼을 '선택'하는 것이 유리한 경우{+}
<검색조건1> where 거래일자 = :a and 상품번호 = :b <검색조건2> where 거래일자 = :a and 고객번호 = :b |
=>사용빈도를 보고 선택, 빈도까지 같다면, 선택도가 낮은 컬럼(고객번호)를 선택하는 것이 현명
결합인덱스 컬럼간 순서를 정할 때는, 개별컬럼의 선택도보다는 조건절에서 어떤형태로 자주 사용되는지, 사용빈도는 어느 쪽이 더 높은지, 데이터를 빠르게 검색하는 데에 어느쪽 효용성이 더 높은지 등이 더 중요한 판단기준이다.
SQL> create table t
as select rownum a, rownum b, rownum c, rownum d, rownum e
from dual
connect by level <= 100000;
테이블이 생성되었습니다.
SQL> create index t_idx on t(a, b, c, d);
인덱스가 생성되었습니다.
{+}소트오퍼레이션 생략{+}
select * from t where a=1 order by a, b, c;
select * from t where a=1 and b=1 order by c, d;
select * from t where a=1 and c=1 order by b, d;
select * from t where a=1 and b=1 order by a, c, b, d;
SQL> explain plan for
2 select * from t
3 where a between 1 and 2
4 and b not in (1, 2)
5 and c between 2 and 3
6 order by a, b, c, d;
해석되었습니다.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 470836197
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 24 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 24 | 3 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T_IDX | 1 | | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
SQL> explain plan for
2 select * from t
3 where a between 1 and 2
4 and c between 2 and 3
5 order by a, b, c;
해석되었습니다.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 470836197
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 24 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 24 | 3 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T_IDX | 1 | | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
SQL> explain plan for
2 select * from t
3 where a between 1 and 2
4 and b <> 3
5 order by a, b, c;
해석되었습니다.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 470836197
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 24 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 24 | 3 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T_IDX | 1 | | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
{+}Index Full Scan 방식으로 정렬작업 생략{+}
SQL> explain plan for
2 select /*+ index(t) */ * from t
3 where b between 2 and 3
4 order by a, b, c, d;
해석되었습니다.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 3778778741
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 24 | 434 (2)| 00:00:06 |
| 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 24 | 434 (2)| 00:00:06 |
|* 2 | INDEX FULL SCAN | T_IDX | 1 | | 433 (2)| 00:00:06 |
-------------------------------------------------------------------------------------
{+}인덱스로 소트오퍼레이션 대체 불가{+}
(CASE 1)
SQL> explain plan for
2 select * from t where a=1 order by c;
해석되었습니다.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 1454352066
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 24 | 4 (25)| 00:00:01 |
| 1 | SORT ORDER BY | | 1 | 24 | 4 (25)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| T | 1 | 24 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | T_IDX | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
(CASE 2)
SQL> explain plan for
2 select * from t
3 where a=1
4 and b between 1 and 2
5 order by c, d;
해석되었습니다.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 1454352066
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 24 | 4 (25)| 00:00:01 |
| 1 | SORT ORDER BY | | 1 | 24 | 4 (25)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| T | 1 | 24 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | T_IDX | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
(CASE 3)
SQL> explain plan for
2 select * from t
3 where a=1
4 and b between 1 and 2
5 order by a, c, b;
해석되었습니다.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 1454352066
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 24 | 4 (25)| 00:00:01 |
| 1 | SORT ORDER BY | | 1 | 24 | 4 (25)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| T | 1 | 24 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | T_IDX | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
{+}인덱스 설계도 작성을 통한 튜닝 사례{+}
p198 그림 1-57 참고