
기본적으로 데이터들을 Disk에 저장하고, 읽어 올 때 내부 버퍼 캐시에 데이터가 없는 경우 Disk I/O를 발생시켜 데이터를 일거온 뒤 이를 DB 내부 버퍼 캐시에 적재하여 다양한 처리를 진행한다.
이때 Disk I/O의 최소 단위가 되는 것이 Block이다.
디스크에서 Block 단위로 데이터를 읽어와서 버퍼 캐시에 적자하는 과정을 Block I/O라 칭한다.
Oracle을 포함한 모든 DBMS의 I/O는 블록 단위로 이루어진다.
하나의 레코드를 읽더라도 레코드가 속한 블록 전체를 읽는 것인데, 그렇기 때문에 가장 중요한 성능 지표는 액세스하는 블록의 개수이며 옵티마이저 판단에 가장 큰 영향을 미친다.
한 번에 한 블록씩 요청해서 메모리에 적재
인덱스가 보통 Single Block I/O 방식으로 디스크에 접근하여 데이터를 가져온다.
인덱스는 항상 정렬된 상태를 유지하는데, 여기에서 나타나는 정렬의 개념이 특정 블록 레벨에서는 무의미해진다. (논리적 정렬 구조 != 물리적 구조)
즉, 하나의 인덱스 구조에 대한 요소들은 여러 Block에 나위어 저장되고 이는 인덱스가 논리적으로 정렬된 순서와 상관이 없다는 의미다.
따라서 논리적으로 정렬된 인덱스 구조를 따라 탐색을 진행하려면 Single Block I/O를 사용해야된다.
Single Block I/O 방식을 통해 읽어내야 할 데이터의 수가 많다면, 호출 건당 비효윻이 누적된다.
따라서 읽어내야 할 데이터가 전체 데이터에 비해 꽤 많다면 해당 방식을 사용하는 것이 오히려 더 느릴 수 있다.
인덱스를 이용한 스캔이 모든 경우에 대해 더 빠른 선택지가 아닌 이유가 바로 이 것이다.
이런 경우에는 Multi Block I/O를 통해 호출을 줄이는 것이 더 나은 선택지가 된다.
인덱스를 활용할 수 있는 경우에 옵티마이저가 전체 테이블을 읽는 이유이다.
Index Fast Full Scan 방식은 인덱스를 활용하면서도 Multi Block I/O 방식을 사용한다.
인덱스의 논리적 정렬 구조를 완전히 무시한 채, 여러 Block을 한 번에 버퍼에 가져와 일거내는 방식이다.
정렬 구조를 무시하기 때문에 버퍼를 읽어왔을 땐 정렬 상태가 유지되지 않는다.
정렬이 유지되지 않는 인덱스 스캔이 무슨 의미일까 싶지만, Query에 포함된 모든 칼럼이 인덱스에 존재하는 경우 이를 Multi Block I/O 방식으로 읽어올 수 있기 때문에 활용되는 방식이다.
I/O Call이 발생한 시점에 인접한 블록들을 같이 읽어 메모리에 적재한다.
Full Scan과 같이 저장된 순서에 따라 읽을 때는 허용하는 범위 내에서 인접한 블록을 읽는 것이 유리하다.
인접한 블록은 한 Extent 범위 내의 블록을 말한다. 즉, Multi Block I/O를 하더라도 Extent의 범위를 넘지 못한다.
Q. 인덱스를 사용해 조회할 데이터의 데이터 셋들의 ROWID 목록을 가지고 Multi Block I/O를 통해 한 번에 여러 블록을 읽어올 수는 없을까?
A. 인덱스를 통해 얻은 ROWID는 논리적으로 정렬되어 있지만, 물리적으로는 서로 다른 파일/Extent/블록에 산개되어 있다.
Multi Block I/O는 한 번의 I/O Call로 물리적으로 연속된 블록만 읽을 수 있기 때문에, 이러한 산개된 ROWID들을 하나의 Multi Block I/O로 묶는 것은 구조적으로 불가능하다.
따라서 인덱스 기반 테이블 접근은 Single Block I/O(랜덤 I/O) 방식으로 수행한다.