ROWID 포맷

  • 제한 ROWID:
    • 데이터파일 번호 + 블록 번호 + 블록 내 로우 번호
    • 오라클 초기 버전부터 사용
  • 확장 ROWID:
    • 오브젝트 번호 + 데이터파일 번호 + 블록 번호 + 블록 내 로우 번호
    • (Oracle 8i~)

둘 중 어느 포맷을 사용하는지는 오브젝트 유형에 따라 다르다.

ROWID는 인덱스 구성요소가 아니라, 인덱스 엔트리가 테이블 로우를 가리키기 위한 주소 정보다.

테이블스페이스는 인덱스 ROWID 구성요소가 아니다.

인덱스 ROWID 를 이용한 테이블 액세스

인덱스 ROWID (그림에서 실선) 은 테이블 레코드와 직접 연결된 구조가 아니다. 데이터 파일 상에서 테이블 레코드를 찾아가기 위한 논리적인 주소 정보다.

인덱스 ROWID에 포함된 데이터 블록 주소 (=데이터파일번호+블록번호) 는 디스크 상의 블록 주소지만, 블록을 매번 데이터파일에서 읽는다면 성능은 이루 말할 수 없이 느리다. I/O 성능을 위한 버퍼캐시 활용이 필수인 이유다.

ROWID 가 가리키는 블록을 버퍼캐시에서 먼저 찾아보고 (그림에서 점선), 못 찾을 때만 데이터파일에서 읽는다.

  • 물론 버퍼캐시에 적재한 후에 읽는다.

캐시에서 블록을 읽을 때는 읽고자 하는 데이터 블록 주소를 해시 함수에 입력해서 해시 체인을 찾고 거기서 버퍼 헤더를 찾는다. 캐시에 적재할 때와 읽을 때 같은 해시 함수를 사용하므로 버퍼 헤더는 항상 같은 해시 체인에 연결된다. 반면, 실제 데이터가 담긴 버퍼 블록은 매번 다른 주소에 캐싱되는데, 그 메모리 주소값을 버퍼 헤더가 가지고 있다.

버퍼캐시는 시스템 공유 메모리에 위치하므로 액세스를 직렬화하기 위한 Lock 메커니즘이 작동한다. 따라서 버퍼캐시에서 블록을 읽을 때마다 Latch 와 Buffer Lock 을 획득해야 한다. 동시 액세스가 심할 때는 Latch 와 Buffer Lock 에 대한 경합까지 발생하므로, 인덱스 ROWID 를 이용한 테이블 액세스는 생각보다 고비용 구조다.

(인덱스 손익분기점) 데이터가 커질수록 왜 “인덱스 손익분기점이 내려가는가”

일반적으로 “데이터가 늘면 Full Scan 비용이 커지므로 인덱스가 더 유리해져서 손익분기점이 올라갈 것”처럼 생각하기 쉽다. 하지만 실제로는 테이블이 커질수록 인덱스 손익분기점이 내려가는(= 그래프가 좌측으로 이동하는) 경향이 나타날 수 있다.

그 이유는 크게 두 가지다.

클러스터링 팩터(Clustering Factor)가 나빠진다 테이블이 작을 때는 같은 값(또는 인접 키 값)의 레코드가 테이블 블록에 모여 있을 가능성이 높다. 하지만 테이블이 수천만~수억 건 규모로 커지면, 인덱스로 읽는 키 값이 테이블 블록에 “인접하게 모여 있을” 가능성이 급격히 낮아지고, 결과적으로 ROWID 기반 테이블 랜덤 액세스가 더 랜덤해져 디스크 I/O가 증가한다.

버퍼캐시 히트율이 낮아진다 버퍼캐시 크기는 일정한데 테이블은 계속 커지므로, 테이블이 커질수록 메모리에 적재되는 데이터 비율이 줄고 디스크 I/O 비중이 커진다. 특히 인덱스 기반 접근은 테이블을 랜덤하게 방문하기 때문에, 디스크 I/O Call 부하가 커지면서 인덱스 접근 비용이 예상보다 많이 증가한다.

따라서 데이터가 늘 때의 Full Scan 비용 상승보다, CF 악화 + 버퍼캐시 히트율 저하로 인덱스 접근 비용이 더 크게 증가할 수 있으며, 그 결과 손익분기점이 내려가는 현상이 “의외”처럼 보일 수 있다.

Batch I/O

ROWID를 이용한 테이블 랜덤 액세스는 생각보다 고비용 구조다. 인덱스를 이용해 대량 데이터를 조회하면 디스크 랜덤 I/O가 증가해 성능이 나빠질 수 있다.

이를 개선하기 위해 오라클에는 배치 I/O(Batch I/O) 개념이 있다.

  • 인덱스로 테이블을 액세스하다가,
  • 버퍼캐시에서 블록을 못 찾으면 보통 즉시 디스크에서 읽는데,
  • 배치 I/O가 작동하면 테이블 블록에 대한 디스크 I/O Call을 즉시 수행하지 않고 미뤘다가
  • 일정량이 쌓이면 한꺼번에 처리한다.

이 경우 실행계획에 TABLE ACCESS BY INDEX ROWID BATCHED 처럼 BATCHED 키워드가 표시된다.

주의할 점:

  • 배치 I/O가 작동하더라도 인덱스를 이용한 부분범위 처리가 “완전히 불가능해지는 것”은 아니다.
  • 다만 디스크에서 읽어오는 구간에서는 출력 순서가 인덱스 정렬 순서와 달라질 수 있다.
  • ORDER BY가 있으면 정렬이 강제되므로, 배치 I/O가 작동하더라도 결과 순서는 ORDER BY로 보장된다(대신 정렬 비용은 발생).