인덱스는 추가적인 쓰기 작업과 저장 공간을 활용하여 데이터베이스 테이블의 검색 속도를 향상시키기 위한 자료구조입니다.
조회하는 테이블의 데이터가 방대한 경우, 모든 데이터를 순차적 검색(full-scan)할 경우 시간이 오래 걸립니다.
이 때 어떤 데이터가 어디에 위치해 있는지에 대한 정보를 인덱스를 통해 저장하면, 검색 시 성능을 높일 수 있습니다.
동작 원리
테이블의 특정 컬럼에 인덱스를 걸면, 해당 컬럼의 데이터들은 정렬이 되어 별도의 메모리 공간에 데이터의 물리적인 주소와 함께 저장됩니다.
이후 조회 시, 인덱스에서 조회하고자 하는 데이터가 있는지 먼저 확인합니다. 있다면 물리적 주소로 이동하여 데이터를 가져오고, 없다면 full-scan 합니다.
정렬된 데이터에서 검색하기 때문에 일반적인 조회속도보다 빠릅니다.
예를들어, id와 create_date 라는 컬럼을 인덱스로 걸었다고 한다면, 해당 데이터는 인덱스로부터 데이터를 검색하게됩니다.
✅ 장점
- 테이블의 조회속도를 향상시켜 시스템 부하를 줄일 수 있습니다.
- 조건 검색 쿼리의 경우 효율성을 높이고, 정렬에서도 효과를 보입니다. 미리 데이터를 정렬하여 관리하기때문에, order by의 과정을 생략할 수 있습니다. (정렬되어 있기 때문에 시작값과 끝값으로 최댓값과 최솟값을 쉽게 가져올 수 있습니다.)
- 데이터 중복도가 낮은 컬럼 (=cardinality(고유값을 가지는 정도)가 높은 컬럼)에 인덱스를 거는 것이 좋습니다. 예를들어 성별 컬럼에 인덱스를 걸 경우, 남자와 여자라는 2개 값만 있는 만큼 값이 중복되기 때문에 검색할 대상이 증가하게 됩니다.
✅ 단점
- 인덱스를 저장하기 위해서는 DB의 10%정도 해당하는 저장공간을 사용해야 합니다.
- CRUD 작업이 빈번한 컬럼에 인덱스를 사용하면 성능이 저하됩니다.
- 인덱스는 빠른 검색을 위해 가장 최근버전의 데이터들을 정렬시킨 상태로 유지해야 합니다. 이 때, 인덱스가 적용된 컬럼에 CRUD 작업이 진행된다면 원본 테이블 뿐만 아니라 인덱스에도 CRUD 작업이 필요하게 됩니다.
- 너무 많은 인덱스를 생성한다면 CRUD시 부하가 발생해 전체적인 DB 성능을 저하시키기 때문에, 쓰지 않는 인덱스는 삭제하는 주기적인 관리가 필요합니다.
✔️ 사용하기 적절한 컬럼
- CRUD(Insert, Update, Delete)가 자주 발생되지 않는 컬럼
- join, where, order by 에 자주 사용되는 컬럼
- 데이터의 중복도 가 낮은 컬럼 (=cardinality가 높은 컬럼)
- 전체 데이터 중 10~15% 이하의 데이터를 처리하는 경우
인덱스 자료구조
1️⃣ B-Tree/B+Tree
MySQL의 InnoDB 스토리지 엔진은 B+Tree 구조(B-Tree 개선)를 사용합니다.
✔️ 특징
- Rooot node , Leaf node, Non-leaf node, LinkedList로 이루어져 있습니다.
- root node에서 시작해 non-leaf nodes를 거쳐 leaf node를 탐색합니다.
- B-Tree는 모든 노드에 데이터가 존재하는 구조입니다. 반면 B+tree는 leaf node에 키와 값이 저장되고, internal node에는 키만 저장됩니다.
✅ 장점
- 모든 노드의 키는 항상 정렬된 상태(오름차순)를 유지합니다.
- B-Tree는 전체 탐색을 해야 하지만, B-Tree는 키를 통해 데이터가 존재하는 리프노드만 한 번 선형탐색하면 되기 때문에 속도가 빠릅니다.
- 새로운 데이터의 삽입/삭제가 간단합니다.
- 범위 쿼리, 정렬된 결과의 반환, 부분검색 등 다양한 쿼리 작업을 효과적으로 처리할 수 있습니다.
2️⃣ 해시테이블
key, value구조로 데이터를 관리하여 해시함수 기반으로 key값을 생성하는 구조입니다.
✅ 장점
- key에 해당하는 value를 찾기 위해 해시 함수를 한 번만 실행하면 되기 때문에, 여러 노드를 읽어야 하는 B+Tree보다 검색 속도가 빠릅니다.
- 데이터에 해시 함수를 적용하여 저장하기 때문에 키값의 크키가 줄어들어 가용성이 좋습니다.
✅ 단점
- 반면, 해시 함수를 기반으로 데이터를 검색하기 때문에 데이터를 정렬하지 않습니다. 따라서 부등호를 이용한 조건 조회가 불가능합니다.
- 데이터를 해시 함수를 사용하여 무작위로 배치하므로 정렬된 결과를 얻는 것이 어려우며, 범위를 지정하여(범위 검색) 여러 값을 찾는 것이 어렵습니다.