인덱스의 기본 개념
인덱스는 책에 있는 색인과 같은 기능입니다.
어떤 책이 있다고 했을 때, 한라산이라는 단어가 나오는 페이지를 찾고 싶다면 색인을 이용해서 빠르게 찾을 수 있습니다. 인덱스도 데이터베이스에서 색인과 비슷한 역할을 수행합니다.
간략하게 인덱스를 사용함으로써 얻게 되는 장점과 단점을 작성해보겠습니다.
장점
- 탐색 속도가 빨라질 수 있다.
- 즉 시스템 전체의 성능 향상으로 이어질 수 있다.
단점
- 색인처럼 인덱스를 위한 별도의 공간이 필요하므로 추가 메모리를 사용한다.
- 인덱스를 작성할 시간이 필요하다.
- 데이터의 변경 작업이 자주 일어난다면 인덱스 수정으로 인해 성능이 나빠질 수 있다.
인덱스는 두 가지 종류가 있습니다.
- 클러스터링 인덱스
- 논-클러스터링 인덱스 (or 보조 인덱스)
클러스터링 인덱스
위 그림을 보시면 RollNo 라는 인덱스를 확인하실 수 있습니다. 그리고 RollNo의 PageId를 따라가시면 리프 페이지에 데이터가 있는 것을 보실 수 있습니다. 즉 리프 페이지가 데이터 페이지이며, 데이터 페이지가 곧 데이터입니다. 굉장히 직관적입니다.
페이지를 살펴보시면 인덱스를 기준으로 정렬되어 있는 모습도 보실 수 있습니다. 이 때문에 클러스터링 인덱스는 범위 탐색에서 강력한 성능을 발휘합니다.
💡어려우신가요!
위 그림은 B-Tree 자료구조를 기반으로 합니다. 각 상자는 데이터베이스에서 페이지라고 하는 단위입니다. 페이지는 데이터베이스에서 저장되는 최소한의 단위입니다. MySQL은 기본 16Kbyte 크기의 페이지를 가진다고 합니다. 데이터를 한 개만 저장하려고 해도 무조건 하나의 페이지가 필요합니다.
생성
사실 기본키(PRIMARY KEY)는 클러스터링 인덱스를 생성합니다. 그래서 그런지 클러스터링 인덱스는 테이블 당 하나만 설정할 수 있다는 점도 기본키의 특성과 동일합니다. 그 외에도 NOT NULL UNIQUE 제약을 설정하면 해당 칼럼은 클러스터링 인덱스로 설정됩니다.
만약 PRIMARY KEY와 NOT NULL UNIQUE가 동시에 설정되면 PRIMARY KEY가 더 높은 우선순위를 가집니다.
논-클러스터링 인덱스
위 그림은 아까 클러스터링 인덱스에서 보았던 테이블과 동일한 테이블에서 논-클러스터링 인덱스를 적용한 예시입니다.
원래 그림이 이상해서 제가 임의로 수정했습니다..
보시면 이번에는 MobileNo 컬럼이 인덱스로 설정된 것을 볼 수 있습니다. PageId를 따라가시면 리프 페이지에서 다시 PageId+offset을 확인하실 수 있습니다. offset은 페이지에서의 행 번호라고 보시면 될 것 같습니다. 예를 들어 1000 + #1 이라는 것은 1000번 페이지에 첫 번째 행을 의미합니다.
데이터 페이지를 살펴보시면 인덱스의 순서에 관계 없이 데이터가 채워져 있는 것을 보실 수 있습니다. 클러스터링 인덱스의 경우 데이터 페이지가 모두 정렬되어 있어야 하지만 논-클러스터링 인덱스의 경우 그럴 필요가 없습니다.
💡 이 차이는 범위 탐색에서 유의미한 성능 차이를 만들어냅니다. 클러스터링 인덱스의 경우 데이터 페이지가 정렬되어 있기 때문에 범위 탐색에 매우 유리한 반면 (캐시의 공간적 지역성 이점도 얻을 수 있습니다) 논-클러스터링의 경우 범위 탐색에서 매우 불리한 것을 알 수 있습니다. 더 많은 페이지를 탐색해야 하기 때문입니다.
생성
기본 INDEX 생성, UNIQUE INDEX 생성, UNIQUE 제약, UNQIEU NULL 제약은 넌-클러스터링 인덱스를 생성합니다.
문제점
모든 인덱스는 INSERT 작업이 일어날 때 성능이 급격히 느려질 수 있다는 단점이 있습니다. INSERT 작업은 어쩔 수 없이 INDEX 수정 작업을 동반하고, 페이지가 모두 가득 찬 경우 페이지 분할 작업으로 인해 성능이 안 좋아질 수 있습니다. 다만 보편적으로 실제 비즈니스 환경에서 읽기 : 쓰기 작업은 8 : 2 정도의 비율이라고 하니 읽기 성능을 위해 쓰기 성능과 타협하는 것이 나쁜 방식은 아닙니다.
'DB' 카테고리의 다른 글
DB 특징, 언어, 카티션 곱 (0) | 2022.10.03 |
---|---|
UNIQUE 제약으로 중복 검사해도 될까? (0) | 2022.09.08 |
MySQL - 재귀 테이블 (0) | 2022.02.25 |