이 시리즈는 RDB의 인덱스와 관련하여 다음의 개념들을 알아봅니다.
- 인덱스
- 다중 컬럼 인덱스
- PK, FK, UK
- mysql explain 인덱스 사용법
인덱스
테이블에 대한 동작의 속도를 높여주는 자료 구조
- 위키피디아
- 특정 열 값이 있는 행을 빠르게 찾는데 사용됩니다.
- SQL 서버가 더욱 좋은 성능을 내도록 하는 전반적인 방법론을 데이터 베이스 튜닝이라고 합니다. 즉, 인덱스는 조회 작업과 관련된 데이터베이스 튜닝을 위해 쓰인다고 볼 수 있습니다.
1. 장단점
장점
- 검색속도 향상 -> 쿼리 부하 감소 -> 시스템 전체 성능 향상
단점
- 자주 반복되는 단어에 사용시 풀스캐닝보다 비효율적
- 반복될 때마다 index를 조회하는 오버헤드 발생
- DB 크기의 약 10% 정도의 추가 공간이 필요
- 처음 인덱스 생성시 시간이 많이 소모
- 데이터 변경 작업(Insert, Update, Delete)이 자주 일어나는 경우 오히려 성능 하락
2. 인덱스의 내부 작동
B-tree 구조
- B-tree의 노드를 MySQL에선 16kB 차지하는 메모리 공간 단위 페이지라고 합니다.
- B-tree 구조를 사용하여 빠르게 SELECT문을 실행할 수 있습니다.
- CUD 작업시 페이지분할이 이루어질 수 있으며, 다수의 페이지 분할이 이루어진다면 부담스러운 작업이 될 수 있습니다.
- 보조 인덱스는 데이터 페이지 자체가 인덱스 페이지가 아니므로 페이지 분할이 CUD 작업에서 덜 이루어져서 클러스터형보다 이러한 작업에서 유리합니다.
이외에도 해시 테이블, R-tree 구조를 사용하는 인덱스도 있다고 합니다.
해시테이블이 아닌 B-tree가 주로 사용되는 이유
결론부터 말하자면 해시는 범위 검색이 불가능하지만, B-tree는 가능하기 때문에 인덱스 생성시 주로 B-tree를 사용하는 것입니다.
해시테이블의 특성상 해시 테이블에 저장된 데이터들은 정렬되어 있지 않습니다. 따라서 >, >=, <, <=, BETWEEN
과 같은 범위 검색이 불가능합니다. 반면, B-tree는 데이터가 모두 정렬되어 있기 때문에 앞서 언급한 연산자들 뿐만 아니라 (%
로 시작하지 않는다는 조건에 한하여) LIKE
까지 포함한 범위 검색에서 빠르게 작업을 수행할 수 있습니다.
해시테이블이 무용지물이기만 한 것은 아닙니다. 해시 테이블은 =, <=>
연산자에 대해서는 O(1)의 시간복잡도를 가지며 매우 빠르게 처리하기 때문에, equailty 비교 연산에서는 O(logN)의 시간 복잡도를 가지는 B-tree 인덱스보다 해시 인덱스가 효율적입니다.
R-tree
N차원의 공간 데이터를 효과적으로 저장하고 지리정보와 관련된 쿼리를 빠르게 수행할 수 잇는 자료구조입니다.
예를 들어, "현재 위치에서 20km 이내의 모든 은행을 찾아라"와 같은 쿼리를 빠르게 수행합니다.
- 특징
- 최소경계사각형(MBR: Minumum Bounding Rectangle)이라는 저장단위에 분할하여 저장합니다
- 완전 균형 트리입니다
3. 인덱스의 종류
MySQL에서 사용되는 인덱스의 종류는 크게 클러스터형, 보조 인덱스로 나뉩니다.
클러스터형 인덱스
- 영어사전과 유사
- 데이터를 열에 맞추어 오름차순으로 자동 정렬
- 범위검색에서 보조형보다 유리
- 인덱스 생성시 오랜 시간이 걸리는 단점
- 자동 생성
- 인덱스 지정 없을 시 기본키 기반으로 클러스터형 인덱스가 자동 생성
- UNIQUE + NOT NULL도 클러스터형 인덱스를 자동 생성
- 단, 기본키가 없는 경우여야 하며, 기본키가 존재한다면 보조 인덱스로 생성됩니다.
- 인덱스 자체의 리프 페이지가 곧 데이터. 즉, 인덱스 자체에 데이터가 포함
- 덕분에 조회 작업에서 보조 인덱스보다 빠릅니다.
- 하나만 존재 가능(반드시 존재할 필요는 없음)
- 어느 열에 클러스터형 인덱스를 생성하는지에 따라서 시스템의 성능이 달라질 수 있습니다.
보조 인덱스
- 교과서 같은 책 뒤의 <찾아보기>와 유사
- 자동생성
- UNIQUE 키마다 1개의 보조 인덱스가 자동 생성
- 여러개 생성 가능
- 데이터 페이지는 그냥 둔 상태에서 페이지에 인덱스를 구성
- 리프 페이지는 데이터가 아닌, 데이터의 주소 값(RID, Row ID)
- 보조 인덱스가 R에 불리하고 CUD에 유리한 이유
- 예를 들어, INSERT 작업의 경우 데이터 페이지에서 단순히 마지막 데이터에 덧붙이기만 수행하면 됩니다.
- 여러개 존재 가능
![보조 인덱스](https://velog.velcdn.com/images/bcj0114/post/da466412-78e1-483f-a16b-c8500857501b/image.png)
클러스터형과 보조형 비교
한 마디로 요약하자면, R 작업은 클러스터형이, CUD 작업은 보조형이 유리합니다.
-
클러스터형이 유리한 점
- 클러스터형은 자동정렬을 사용하여 범위 검색에서 유리합니다.
- 데이터 페이지 자체가 인덱스 페이지로 포함되어 검색 작업에서 보조 인덱스보다 빠릅니다.
-
클러스터형이 불리한 점
- 인덱스 생성시 자동정렬을 하므로 생성 시간이 오래 걸립니다.
-
보조형이 유리한 점
- INSERT, DELETE, UPDATE 작업에서 페이지 분할이 덜 이루어져서 빠릅니다.
클러스터형 인덱스와 보조형 인덱스가 혼합되어 있을 경우
현실에선 PK와 UNIQUE key를 동시에 사용하는 경우가 많아서 두 종류의 인덱스가 혼용되는 경우가 많습니다.
![](https://velog.velcdn.com/images/bcj0114/post/d6edb95c-e8a4-4699-a997-61a0e673fe48/image.png)
![](https://velog.velcdn.com/images/bcj0114/post/4f1aa4e9-54d6-4f10-8158-4a713ca80236/image.png)
혼합된 보조 인덱스에선 데이터의 주소 값이 아닌 클러스터 인덱스의 기본키 값을 저장합니다. 이는 클러스터 인덱스가 수정될 때마다 보조 인덱스가 가르키는 주소값이 변경되는 것을 방지하기 위함입니다.
4. 결론: 인덱스는 언제 사용해야할까?
'테이블의 데이터 구성이 어떻게 되었는지, 어떠한 조회를 많이 사용하는지' 등을 고려하여 인덱스를 사용하여야 합니다.
다음과 같은 인덱스의 특징들을 기억해두면 언제 사용할지에 대한 판단에 도움이 됩니다.
인덱스의 특징
- 열 단위로 생성
- 한 개 혹은 두 개 이상의 열을 조합해서 인덱스를 생성할 수 있습니다.
- WHERE절에서 자주 사용되는 열
- 테이블 조회 시에 WHERE절의 조건에 해당하는 열이 나오는 경우만 인덱스를 주로 사용합니다.
- 가끔 쓰는 경우라면 인덱스를 만드는 것의 비용이 더 클 수 있습니다.
- 데이터의 중복도가 낮은 열
- 성별과 같은 데이터의 종류가 작고 중복도가 높은 경우엔 만들지 않는 것이 낫습니다.
- 외래 키를 지정한 열에는 자동으로 외래 키 인덱스가 생성
- 그리고 쿼리문에서 외래 키 인덱스가 필요할 경우 MySQL이 알아서 외래 키 인덱스를 사용합니다.
- JOIN에 자주 사용되는 열
- INSERT/UPDATE/DELETE 발생 빈도
- 인덱스는 단지 읽기에서만 성능을 향상시키므로, 데이터의 변경이 자주 이루어지는 경우라면 지양하는게 좋습니다.
부록: 문법
http://www.albumbang.com/board/board_view.jsp?board_name=free&no=141
인덱스 생성 문법은 위 링크를 참고하자
참고문헌
- 한빛 미디어 유튜브 채널
- 해시 인덱스 관련
- R-tree 관련