인덱스 기본 사용법은 인덱스를 Range Scan 하는 방법을 의미한다.
색인이 정렬돼 있더라도 가공한 값이나 중간값(중간에 포함된 값)으로는 스캔 시작점을 찾을 수 없다.
그렇다 하더라도 색인을 아예 사용할 수 없는 것은 아니다.
시작점을 찾을 수 없고 멈출 수 없을 뿐이다.
가공한 값이나 중간 값(중간에 포함된 값)을 찾을 때도 색인을 사용할 수 있지만, 색인 전체를 스캔해야 한다.
'인덱스를 정상적으로 사용한다' 는 표현은 리프 블록에서 스캔 시작점을 찾아 거기서부터 스캔하다가 중간에 멈추는 것을 의미한다.
리프 블록 일부만 스캔하는 Index Range Scan을 의미한다.
인덱스 컬럼을 가공해도 인덱스를 사용할 수는 있지만, 스캔 시작점을 찾을 수 없고 멈출 수도 없어 리프 블록 전체를 스캔해야만 한다.
일부가 아닌 전체를 스캔하는 Index Full Scan 방식으로 작동한다.
인덱스 컬럼을 가공했을 때 인덱스를 정상적으로 사용할 수 없는 이유는 인덱스 스캔 시작점을 찾을 수 없기 때문이다.
'Index Range Scan'에서 'Range'는 범위를 의미한다. 일정 범위를 스캔하려면 '시작 지점'과 '끝지점'이 있어야 한다.
IN 조건과 OR 조건에서의 Range Scan
IN 조건은 OR 조건을 표현하는 다른 방식일 뿐이므로, Index Range Scan이 불가능하다.
UNION ALL 방식으로 작성하면, 각 브랜치 별로 인덱스 스캔 시작점을 찾을 수 있으므로 Range Scan이 가능하다.
IN 조건절에 대해서는 SQL 옵티마이저가 IN-List Iterator 방식을 사용한다.
IN-List 개수만큼 Index Range Scan을 반복하는 것이다.
'인덱스를 정상적으로 사용한다' 는 표현은 리프 블록에서 스캔 시작점을 찾아 거기서부터 스캔하다가 중간에 멈추는 것을 의미한다.
OR, IN 조건절은 옵티마이저의 쿼리변환 기능을 통해 Index Range Scan으로 처리되기도 한다.
인덱스를 Range Scan 하기 위한 가장 첫 번째 조건은 인덱스 선두 컬럼이 가공하지 않은 상태로 조건절에 있어야한다.
여기서 주의할 점은 인덱스를 Range Scan 한다고 해서 항상 성능이 좋은 건 아니라는 것이다.
인덱스를 Range Scan 할 수 있는 이유는 데이터가 정렬돼 있기 때문이다.
인덱스가 정렬돼 있기 때문에 Range Scan이 가능하고, 소트 연산 생략 효과도 부수적으로 얻게된다.
인덱스 리프 블록은 양방향 연결 리스트 구조로 되어있다.
오름차순 정렬일 때는 조건을 만족하는 가장 작은 값을 찾아 좌측으로 수직적 탐색을 한 후, 우측으로 수평적 탐색을 한다.
내림차순 정렬일 때는 조건을 만족하는 가장 큰 값을 찾아 우측으로 수직적 탐색을 한 후, 좌측으로 수평적 탐색을 한다.