본문 바로가기
스터디/오라클 성능고도화 원리와 해법1

06.I/O 효율화 원리 - 04. Prefetch

by 취미툰 2020. 2. 12.
반응형

오라클에서 한번의 Fetch Call로 Array 크기만큼 여러 개 레코드를 가져오는 것을 ‘Row Prefetch’라고 설명합니다. 하지만 지금 설명하는 Prefetch는 테이블 prefetch와 인덱스 prefetch를 말합니다.
오라클을 포함한 모든 DBMS는 디스크 블록을 읽을 때 곧이어 읽을 가능성이 높은 블록을 미리 읽어오는 Prefetch 기능을 제공합니다. 디스크 I/O가 비용이 크기 때문에 한번의 I/O Call을 통해 다량의 블록을 퍼 올릴 수 있으면 그만큼 성능향상에 도움이 되기 때문입니다. 앞 절의 Multiblock I/O도 prefetch 기능 중하나라고 할 수 있습니다. 지금 설명할 prefetch와 다른점은 한 익스텐트에 속한 인접한 블록들을 Prefetch 한다는 점입니다.
Prefetch는 한번에 여러 개 SIngle Block I/O를 동시 수행하는 것을 말합니다. 인적하지 않은 블록, 즉 서로 다른 익스텐트에 위치한 블록을 배치방식으로 미리 적재하는 것을 말합니다. I/O Call 을 병렬 방식으로 동시에 여러 개 수행하는 것이므로 읽어야 할 블록들이 서로 다른 디스크 드라이브에 위치한다면 Prefetch에 의한 성능 향상을 더욱 배가됩니다.
이 기능은 곧 읽을 가능성이 높은 블록들을 미리 적재했을 때만 성능 향상에 도움을 줍니다. 이미 적재했는데 실제 사용으로 연결되지 못하면 버퍼 캐시 효율만 나빠집니다. 오라클은 미리 적재했을 때 효과를 얻을 수 있는 오퍼레이션에만 이 기능을 적용하지만, 그럼에도 Prefetch한 블록들이 실제 액세스로 연결되지 못한 채 캐시에서 밀려나는 비율이 높다면 더는 이 기능이 작동되지 못하도록 정지시켜 버립니다. Prefetch된 블록들을 모니터링하는 기능은 CKPT프로세스가 맡습니다.(sys.x$kcbkpfs 뷰 참조)
앞으로 읽어야 할 블록들을 미리 적재하는 기능이므로 시스템 전반의 디스크 경합을 줄여주기보다, I/O를 위한 시스템 Call을 줄이고 개별 쿼리의 수행 속도를 향상시키는데 주로 도움을 줍니다. 데이터 블록을 읽는 도중에 물리적인 디스크 I/O가 필요할 때면 서버 프로세스는 I/O 서브세스템에 I/O Call을 발생시키고 잠시 대기 상태에 빠집니다. 어차피 대기 상태에서 잠시 쉬어야 하므로, 곧이어 읽을 가능성이 높은 블록들을 버퍼 캐시에 미리 적재해 놓는다면 대기 이벤트 발생횟수를 그만큼 줄일 수 있습니다.
Prefetch는 db file parallel read 대기 이벤트로 측정됩니다.

(1)인덱스 Prefetch
오라클 7.2버전부터 사용돼 온 기능입니다. 브랜치 블록에서 앞으로 읽게 될 리프 블록 주소를 미리 얻을 수 있으므로 I/O Call이 필요한 시점에 미리 캐싱해 두는 것이 가능합니다.
인덱스 Prefetch기능이 가장 효과적일 수 있는 상황은 Index Full Scan이 일어날 때입니다. 부분범위처리 방식으로 중간에 멈추지만 않는다면 모든 인덱스 리프 블록을 읽게 되기 때문입니다. 그런데 Index Full Scan시 Prefetch방식으로 I/O하려면 리프 블록 위쪽에 있는 브랜치 블록들을 추가로 읽어야 하기 때문에 Prefetch 하지 않을 때보다 I/O가 약간 더 발생합니다. (일반적인 Index full scan시에는 가장 왼쪽 브랜치 블록만 읽습니다.)
아래는 인덱스 PRefetch를 제어하는 파라미터입니다.
_index_prefetch_factor : 기본 값은 100이며, 이 값을 더 작게 설정할수록 옵티마이저는 인덱스 Prefetch를 더 선호하게 됩니다.
_db_file_noncontig_mblock_read_count : 한 번에 최대 몇 개 블록을 Prefetch할지를 지정합니다. 1로 지정하면 Prefetch 기능이 정지됩니다.

(2)테이블 Prefetch
테이블 Lookup Prefetch 또는 데이터 블록 Prefetch라고도 합니다. 인덱스를 경유해 테이블 레코드를 액세스하는 도중 디스크에서 캐시로 블록을 적재해야 하는 상황이 발생할 수 있는데, 그때 다른 테이블 블록까지 미리 적재해 두는 기능입니다.
Random 액세스 성능을 향상시키려고 버퍼 Pinning과 테이블 Prefetch같은 기능을 사용합니다. 버퍼 Pinning은 Random 액세스에 의한 논리적 블록 요청 횟수를 감소시키고, 테이블 Prefetch는 디스크 I/O에 의한 대기 횟수를 감소시킵니다.
이 기능은 인덱스 클러스터링 팩터가 나쁠 때 특히 효과를 발휘합니다. 클러스터링 팩터가 나쁘면 논리적 I/O가 증가할 뿐 아니라 디스크 I/O도 많이 발생하기 때문입니다. 아래는 테이블 Prefetch를 제어하는 파라미터입니다.
_table_lookup_prefetch_size : 기본값은 40
_table_lookup_prefetch_thresh : 기본값은 2
_multi_join_key_table_lookup : 기본값은 true
DB2,SQL Server도 Prefetch기능을 제공하지만 작동방식이 조금 다릅니다. 인덱스에서 읽은 집합을 실시간으로 정렬해 클러스터링 팩터를 좋게 만든 상태에서 테이블을 액세스하는 것으로 작동합니다. 한 번 액세스해 그곳에 저장된 레코드를 모두 읽어들이므로 Random 액세스의 비효율을 완전히 제거할 수 있습니다.



반응형

댓글