인덱스 튜닝
2021. 12. 28. 21:52
인덱스 튜닝
- 책에서는 랜덤 I/O를 줄이는 것을 강조함
3.1 테이블 엑세스 최소화
- 이번장에서는 테이블 랜덤 엑세스를 최소화하는 구체적인 방법들을 소개
3.1.1 테이블 랜덤 엑세스
- 인덱스로 검색하는데 느린 이유는 무엇일까?
- 인덱스에 대한 이해도가 필요하다.
- 물리적 주소 vs 논리적 주소
- 물리적 주소 : 실제 물리적 주소
- 논리적 주소 : 논리적 의미를 담고 있음
인덱스 ROWID는 물리적 주소일까 논리적 주소일까?
인덱스를 사용하는 이유는 ROWID를 빠르게 얻기 위함이다.
ROWID가 데이터파일 번호, 오브젝트 번호, 블록 번호 같은 물리적 요소로 이루어져 있기 때문에 물리적 주소라고 생각한다면 완전히 틀린 것은 아니다.
하지만 ROWID는 논리적 주소에 가깝다.
인덱스에서 ROWID를 찾자마자 바로 데이터를 찾아다주는 것이 아니다
ROWID를 확인 후 디스크에 접근하기 때문에 논리적 주소 정보라고 할 수 있다.
- 메인메모리 DB와 비교
- 메인메모리 DB의 경우 메모리상의 주소정보를 인덱스로 갖는다.
- 그 말은 인덱스를 경우해 테이블을 바로 융엑세스 할 수 있다는 의미다.
- 오라클은 테이블 블록이 수시로 버퍼캐시에서 밀려났다가 다시 캐싱되기 때문에 인덱스에서 포인터로 직접 연결할 수 없는 구조다.
- 메모리 주소 정보(포인터)가 아닌 디스크 주소 정보(Data Block Address)를 이용해 해시 알고리즘으로 버퍼 블록을 찾아감
- I/O 메커니즘 복습
- DBA(=데이터파일번호 + 블록번호)는 디스크 상에서 블록을 찾기 위한 주소 정보
- 매번 디스크에서 블록을 읽을 수 없으니 버퍼 캐시를 활용해야 함
- 디스크 접근 전 DBA를 해시 함수에 넣은 다음 해시 체인을 찾고 버퍼 헤더를 찾는다.
- 버퍼 헤더는 실제 데이터가 담긴 버퍼 블록의 주소값을 가지고 있다.
3.1.2 인덱스 클러스터링 팩터
- 클러스터링 팩터(Clustering Factor, CF)는 특정 컬럼을 기준으로 같은 값을 갖는 데이터가 서로 모여있는 정도를 의미함
- 예를 들어 '거주지 = 제주'인 고객 데이터가 물리적으로 근접해 있는 것과 같다.
- 인덱스 정렬순서와 물리적 접근도를 확인하면 된다.
- 인덱스 클러스팅 팩터 효과
- 인덱스 ROWID로 테이블을 엑세스 할 때, 오라클은 래치 획득과 해시 체인 스캔과정을 거쳐 어렵게 찾아간 테이블 블록에 대한 포인터를 바로 해제하지 않고 일단 유지한다. 버퍼 Pinning이라 한다.
- 이 상태에서 다음 인덱스 레코드를 읽는데 우연히 직전과 같은 테이블 블록을 가리키면 래치 획득과 해시 체인 스캔과정을 스킵하기 때문에 IO 효율이 좋아짐
3.1.3 인덱스 손익분기점
- 인덱스 ROWID를 이용한 테이블 엑세스는 고비용 구조이다.
- 읽어야 할 데이터가 일정량을 넘는 순간 table full scan보다 느려진다.
- 이 느려지는 시기가 손익분기점이다.
- Table Full Scan은 성능이 일정하다.
- 반면 인덱스 스캔은 몇 건을 추출하느냐에 따라 성능이 천차만별로 달라진다.
- 인덱스를 이용한 테이블 엑세스가 Table Full Scan보다 느려지게 만드는 핵심적인 두 요소
- Table Full Scan은 시퀀셜 엑세스인 반면, 인덱스 ROWID를 이용한 테이블 엑세스는 랜덤 엑세스 방식이다.
- Table Full Scan은 Multiblock IO인 반면, 인덱스 ROWID를 이용한 테이블 엑세스는 Single Block IO이다.
인덱스 스캔 효율화
- 인덱스 스캔 효율성 측정
- SQL 트레이스 사용
Row Source Operation
--------------------------------------------------------------------------
TABLE ACCESS BY INDEX ROWID BIG_TABLE (cr=7471 pr=1466 pw=0 time=22137 us)
INDEX RANGE SCAN BIG_TABLE_IDX (cr=7463 pr=1466 pw=0 time =22328 us)
- cr = 읽은 블록의 개수 (consistent read) (buffer cache에서 읽은 개수)
- pr = physical read (디스크에서 읽은 개수)
- pw = physical write (디스크 블럭 쓰기)
인덱스 엑세스 조건, 인덱스 필터 조건
- 인덱스 엑세스 조건 : 인덱스 스캔 범위를 결정하는 조건절
- 인덱스 필터 조건 : 테이블로 엑세스할지를 결정하는 조건절
옵티마이저의 비용 계산 원리
인덱스 수직적 탐색비용 + 인덱스 수평적 탐색비용 + 테이블 랜덤 엑세스 비용
= 인덱스 루트와 브랜치 레밸에서 읽는 블록 수 +
인덱스 리프 블록을 스캔하는 과정에 읽는 블록 수 +
테이블 엑세스 과정에 읽는 블록 수
인덱스 선행 컬럼이 등치조건이 아닐 때 생기는 비효율
- 인덱스 스캔 효율성은 인덱스 컬럼을 조건절에 모두 등치 조건으로 사용할 때가 가장 좋다.
- 리프 블록을 스캔하면서 읽은 레코드가 모두 테이블 엑세스로 이어지기 때문이다.
- 인덱스 컬럼중 일부가 조건절에 없거나 등치 조건이 아니더라도, 그것이 뒤쪽 컬럼일 때는 비효율 없음
- 인덱스 선행 컬럼이 조건절에 없거나 부등호, BETWEEN, LIKE 같은 범위검색 조건이면, 인덱스를 스캔하는 단계에서 비효율이 생긴다.
- BETWEEN을 IN-List로 전환하면 효과를 얻는 경우도 있다.
3.4 인덱스 설계
- 인덱스 설계가 어려운 이유
- 인덱스를 마음대로 생성하면 테이블마다 인덱스가 수십 개씩 달리게 되고 관리비용 뿐만아니라 시스템 부하를 증가시키는 요인이 된다.
- DML 성능 저하 -> TPS 저하
- 데이터베이스 사이즈 증가 -> 디스크 공간 낭비
- 데이터베이스 관리 및 운영 비용 상승
- 예를 들어 테이블에 인덱스가 6개 달려있다면, 테이블에 새로 데이터가 추가될 때 인덱스에도 각각 데이터를 추가하고 정렬해줘야 한다.
- 데이터를 지우는 상황에서도 마찬가지다.
- 인덱스를 마음대로 생성하면 테이블마다 인덱스가 수십 개씩 달리게 되고 관리비용 뿐만아니라 시스템 부하를 증가시키는 요인이 된다.
- 가장 중요한 두가지 선택 기준
- 조건절에 항상 사용하거나, 자주 사용하는 컬럼을 선정한다.
- ' = ' 조건으로 자주 조회하는 컬럼을 앞쪽에 둔다.
- 스캔 효율성 이외의 판단 기준
- 수행 빈도 (가장 중요)
- 업무상 중요도
- 클러스터링 팩터
- 데이터량
- DML 부하(기존 인덱스 개수, 초당 DML 발생량, 자주 갱신하는 컬럼 여부 등)
- 저장 공간
- 인덱스 관리 비용
- 소트 연산을 생략하기 위한 방법
- ' = ' 연산자로 사용한 조건절 컬럼 선정
- ORDER BY 절에 기술한 컬럼 추가
- ' = ' 연산자가 아닌 조건절 컬럼은 데이터 분포를 고려해 추가 여부 결정
'skill > 데이터베이스 튜닝' 카테고리의 다른 글
인덱스 기본 (0) | 2021.12.08 |
---|---|
SQL 처리 과정과 I/O (0) | 2021.11.29 |