책/친절한 sql 튜닝
2장. 인덱스 - 인덱스 기본 사용법
ballde
2023. 3. 27. 20:59
인덱스를 사용한다는 것
- 인덱스를 정상적으로 사용한다 라는 표현은 리프 블록에서 스캔 시작점을 찾아 거기서부터 스캔하다가 중간에 멈추는 것을 의미합니다. ⇒ index range scan
- 인덱스 컬럼을 가공해도 인덱스를 사용할 수 있지만 스캔 시작점을 찾을 수 없고 멈출 수 없어리프 블록 전체를 스캔해야한다. ⇒ index full scan
그렇다면 index range scan을 할 수 없는 이유는?
시작점을 찾을 수 없기 때문이다.
예시
where 생년월일 between '20070101' and '20070131'
위 예시는 시작점과 끝 지점을 알 수 있다.
where substr(생년월일, 5, 2) = '05'
위 예시는 시작점과 끝 지점을 알 수 없다.
nvl(ifnull), like, or 등도 마찬가지이다.
select *
from customer
where 고객명 = ...
union all
select *
from customer
where 전화번호 = ...
하지만 위처럼 고객명, 전화번호가 index가 걸려있고 union all로 하게 되면 각자 index range scan이 된다.
where 전화번호 in (tel1, tel2)
in 조건은 or 조건을 표현하는 다른 방식이다.
그래서 in 조건절에 대해서는 sql 옵티마이저가 in-list iterator방식을 사용한다. 즉 in-list 개수만큼 index range scan을 반복하게 된다.
더 중요한 인덱스 사용 조건
[소속팀 + 사원명 + 연령]순으로 인덱스가 걸려있는데 사원명으로 조건을 걸게된다면?
where 사원명 = '홍길동'
소속팀이 첫번째 순서기 때문에 사원명=’홍길동’은 여기저기 흩어져있다. ⇒ 시작점을 알 수가 없다.
즉 index range scan하기 위한 가장 첫 번째 조건은 인덱스 선두 컬럼이 조건절에 있어야한다.
인덱스를 이용한 소트 연산 생략
인덱스가 Range scan할 수 있는 이유는 정렬되어 있기 때문이다.
[장비번호 + 변경일자 + 변경 순번]순으로 인덱스 되어있다.
where 장비번호 = 'C' and 변경일자 = '20180316'
결과 집합은 변경순번 순으로 출력된다. ⇒ 이미 인덱스 걸 때 정렬되어 있기 때문에 order by를 따로 실행하지 않음(생략)
하지만 주문일자 또는 주문번호를 가공해서 사용할 경우 order by 연산 단계가 추가된다.
select-list에서 컬럼 제공
[장비번호 + 변경일자 + 변경순번]순일 경우
select min(변경순번)
from 상태변경이력
where 장비번호 ='C' and 변경일자 = '20180315'
- 수직적 탐색을 통해 조건을 만족하는 가장 왼쪽 지정에서 첫번째 값이 최소이기 때문에 정렬연산을 따로 하지 않는다.
- max도 마찬가지다.
- 즉 인덱스 리프 블록의 왼쪽(min) 또는 오른쪽(max)
자동 형변환
select *
from customer
where to_number(생년월일) = 19820201
- 인덱스 컬럼이 가공됐기 때문에 full scan 일어남
- 또한 LIKE, BETWEEN조건을 사용하면 인덱스 스캔 효율이 안좋음
- 즉 데이터 형식을 정확히 지정해주는 코딩 습관이 필요!