인덱스(Index)란?
데이터베이스의 테이블에 대한 검색 속도를 향상시켜주는 자료구조이다.
테이블의 특정 컬럼(Column)에 인덱스를 생성하면, 해당 컬럼의 데이터를 정렬한 후 별도의 메모리 공간에 데이터의 물리적 주소와 함께 저장된다. (인덱스는 테이블 내의 1개의 컬럼, 혹은 여러 개의 컬럼을 이용하여 생성될 수 있다.)
컬럼의 값과 물리적 주소를 (key, value)의 한 쌍으로 저장한다.
책에서의 목차 혹은 색인 이라고 생각하면 된다.
ex)
오른쪽 테이블만 존재한다고 가정했을 때 : 정렬이 안되어 있는 데이터에서 내가 원하는 Discipline을 찾기 위해서는 테이블의 전체 데이터에 대한 select를 진행해야 한다. → 데이터가 많고 조회가 잦다면 성능이 떨어질 것이다.
인덱싱이 되어서 인덱스 테이블이 생성되었다면 : Discipline 컬럼에 대해 인덱싱을 하여 데이터가 정렬된 상태에서 컬럼의 값과 물리적 주소를 저장 → 내가 원하는 값으로 신속하게 이동이 가능하게 된다.
인덱스(Index)의 장단점
장점
1.
테이블을 검색하는 속도와 성능이 향상된다.
2.
시스템의 전반적인 부하를 줄일 수 있다.
3.
인덱스에 의해 데이터들이 정렬된 형태를 갖기 때문에 '풀 테이블 스캔(Full Table Scan)' 작업이 필요한 기존 테이블과 달리 조건에 맞는 데이터를 빠르게 찾을 수 있다.
4.
ORDER BY 문이나 MIN/MAX 같은 경우도 이미 정렬이 되어 있기 때문에 빠르게 수행할 수 있다.
단점
1.
인덱스를 관리하기 위한 추가 작업이 필요하다.
인덱스가 적용된 컬럼에 삽입(INSERT), 삭제(DELETE), 수정(UPDATE) 작업을 수행하면 다음과 같은 추가 작업이 필요하다.
•
INSERT : 새로운 데이터에 대한 인덱스를 추가
•
DELETE : 삭제하는 데이터의 인덱스를 사용하지 않는다는 작업 수행 (인덱스를 제거하는 것이 아니라 '사용하지 않음'으로 처리하고 남겨둔다.)
•
UPDATE : 기존의 인덱스를 사용하지 않음 처리, 갱신된 데이터에 대한 인덱스 추가
2.
추가 저장 공간 필요
데이터의 잦은 수정이 발생하는 테이블이라면 수정 때마다 인덱스가 쌓여서 인덱스가 과도하게 쌓인다 → 추가 저장 공간을 많이 필요로 할 수도 있다.
3.
잘못 사용하는 경우 오히려 검색 성능 저하
성별 컬럼 처럼 값의 범위가 작고 중복이 많은 컬럼일수록 인덱싱을 해서 오히려 성능이 낮아질 수도 있다.
인덱스의 자료구조
1.
해시 테이블(Hash Table)
해시 테이블은 key와 value를 한 쌍으로 데이터를 저장하는 자료구조이다.
인덱스는 (key, value) = (컬럼의 값, 데이터의 위치) 의 쌍으로 표현하며, key값을 이용해 대응되는 value값을 구하는 방식이다. 평균적으로 O(1)의 매우 빠른 시간만에 원하는 데이터를 탐색할 수 있는 구조이다.
해시 테이블을 이용한다면 구현하는데, 해시 테이블은 실제로 인덱스에서 잘 사용되지 않는다.
특정 기준으로 대소비교를 하는 부등호 연산이 자주 사용되는 데이터베이스와 달리 헤시 테이블은 등호 연산에 최적화되어 있기 때문에 실제로 인덱스에서는 잘 쓰지 않는다.
2.
B+Tree
기존의 B-Tree는 어느 한 데이터의 검색은 효율적이지만, 모든 데이터를 한 번 순회하는 데에는 트리의 모든 노드를 방문해야 하므로 비효율적이다. 이러한 B-Tree의 단점을 개선시킨 자료구조가 B+Tree이다.
B-Tree란?
B+Tree는 오직 leaf node에만 데이터를 저장하고 leaf node가 아닌 node에서는 자식 포인터만 저장한다. → B-tree에 비해 메모리를 더 확보할 수 있다.
그리고 leaf node끼리는 Linked list로 연결되어있다. → full scan시에 더 빠르다.
또, B+Tree에서는 반드시 leaf node에만 데이터가 저장되기 때문에 중간 node에서 key를 올바르게 찾아가기 위해서 key가 중복될 수 있다.
B+Tree 예시. 데이터는 리프노드에만 존재한다.
삽입 과정
삭제 과정
B+ tree 시뮬레이션
인덱스 종류
Clusted Index(클러스터형 인덱스)
테이블당 1개만 생성 가능하며 해당 컬럼을 기준으로 테이블이 물리적으로 정렬된다. → 리프노드가 필요없게 되며 추가적인 공간이 필요하지 않음.
PRIMARY KEY 설정 시 자동으로 생성되며, 이 컬럼은 데이터 변경시 항상 정렬을 유지한다.
select 쿼리 성능은 좋으나, 데이터 작업이 변경 일어날 때 프라이머리 키 관련 작업을 추가적으로 해야하므로 성능이 떨어지게 된다.
클러스터 인덱스 사용시 주의사항
클러스터 인덱스를 생성하게 되면, 모든 보조 인덱스가 프라이머리 키를 포함하므로 프라이머리 키의 크기가 보조 인덱스에 영향을 끼친다.
넌 클러스터 인덱스
테이블당 여러 개를 생성할 수 있다.
테이블의 페이지를 정렬하지 않고 새로운 공간에 인덱스 페이지를 생성하므로, 클러스터 인덱스보다 많은 공간을 차지하는 단점이 있다.
데이터 행과 인덱스는 분리된 구조를 가진다.
클러스터형 인덱스와 달리 인덱스 페이지 주소공간 부분은 '페이지 번호 + #오프셋'이 기록되어 바로 데이터 위치를 가리킨다.
ex) indexTest2는 102번 페이지의 두 번째(#2)에 데이터가 있다고 기록한다.
인덱스에 컬럼이 하나만 걸려있으면 단일 인덱스, 두개 이상은 복합 인덱스라고 한다.
쿼리를 충족하는데 필요한 모든 데이터가 인덱스에 있어 테이블 접근이 필요하지 않은 인덱스를 커버링(또는 커버드) 인덱스라고 한다.