✨ B*Tree 인덱스를 정상적으로 사용하기 위해서는 범위 스캔 시작지점을 찾기 위하여 루트 블록부터 리프 블록까지의 수직적 탐색 과정을 거쳐야 한다. 만약, 인덱스 선두 칼럼이 조건절에 사용되지 않을 경우 범위 스캔에 대한 시작점을 찾을 수 없기 대문에 옵티마이저는 인덱스 전체 스캔을 하거나 테이블 전체 스캔 방식을 선택한다. 그렇다면 효율적인 인덱스 사용을 위해 어떤 조건이 있고, 어떤 방향으로 해결할 수 있는지 생각해보자.
🪡 범위 스캔 또는 인덱스 사용 불가능한 경우?
1. 범위 스캔이 불가능하거나 인덱스 사용이 아예 불가능한 경우
- 인덱스 선두 컬럼을 조건절에서 가공
- 부정형 비교를 사용 ( <> , not null)
2. 인덱스 칼럼을 가공할 경우
3. 형변환에 문제가 생길 경우
- DBMS에서는 묵시적 형변환을 지원하고 있지만, 종종 문제가 생길 수 있기 때문에 가급적 명시적 형변환을 거치는 것이 좋다.
🧶 테이블 Random 엑세스 최소화
쿼리에서 참조되는 컬럼이 인덱스에 모두 포함되는 것이 아니라면, 테이블 Random 엑세스가 일어나게 된다.
인덱스에 저장되어있는 rowid를 바탕으로 하여 해시 버킷을 찾고 그 안에서 블록 헤더를 찾으는 트리 탐색 메커니즘을 사용하게 되는데, 생각보다 많은 비용을 소모하게 된다.
🐣인덱스 손익분기점?
많은 비용을 처리하는 rowid 방식은 테이블 전체를 스캔할 때보다 느려지는 경우가 있는데, 이와 같이 index Range Scan에 의한 테이블 엑세스가 Table Full Scan보다 느려지는 지점을 '손익 분기점' 이라고 부른다. 예를 들어서 손익분기점이 10%라는 것은 1,000개 중 100개 레코드 이상을 읽을 경우 인덱스를 사용하는 것보다 테이블 전체 스캔이 더 빠르다는 것이다.
🐤테이블 Random 엑세스 최소화 튜닝하기
1. 인덱스 칼럼 추가2. Covered Index - 필요한 모든 칼럼을 인덱스에 포함3. Include Index (Oracle X) - 인덱스 키 외에 미리 지정한 칼럼을 리프 레벨에 함께 저장하는 기능.4. IOT, 클러스터형 인덱스, 클러스터 테이블 활용5. 수동으로 클러스터링 팩터 높이기
🏹 인덱스 스캔범위 최소화 하기
이번에는 Sequential 방식으로 스캔하는 단계에서 발생하는 것과, 해소하는 방법에 대해서 알아보자.
🐣 인덱스 선행 칼럼이 범위조건일 때의 비효율
인덱스 스캔을 할 대, 선행 칼럼 조건절이 누락되거나 범위검색 조건이 사용될 경우 인덱스를 스캔하는 단계에서 비효율이 발생한다.
선행 칼럼에 범위검색 조건을 사용할 경우, 만족하는 값을 전부 찾아야 하기 때문에 조건을 만족하는 레코드까지 스캔하고 버려야 하는 비효율이 발생하게 된다. 이와 같은 경우에는 범위조건을 In-List로 전환하게 되면 큰 효과를 볼 수 있는데, 사용할 때는 깊이가 깊지 않거나 리스트화 시키는 것이 적을 경우에만 사용하는 것이 좋다.
🐤 범위조건을 두개 이상 사용할 때의 비효율
스캔의 양의 적을 때는 차이가 미미하지만, 대량일 때는 상당한 성능 차이를 보일 수 있기 때문에 비교 연산자를 신중하게 선택할 필요가 있다.
그렇기 때문에 LIKE와 같은 연산자를 사용할 경우에는 UNION ALL을 사용하거나 SQL 두개를 만드는 등의 방식으로 해결이 가능하다.