인덱스란?
인덱스는 데이터베이스 테이블에 대한 동작의 속도를 높여주는 자료 구조를 일컫는다.
인덱스는 테이블 내의 1개의 컬럼, 혹은 여러 개의 컬럼을 이용하여 생성될 수 있다.
특정 컬럼에 인덱스를 생성하면, 해당 컬럼의 데이터들을 정렬하여 별도의 메모리 공간에 데이터의 물리적 주소와 함께 저장된다.
쉽게 말하자면 책에 있는 목차를 생각하면 된다.
-> 목차를 보고 바로 원하는 내용으로 가듯, 인덱스를 통해 내가 원하는 데이터의 물리적 주소로 가서 데이터를 가져오는 식으로
동작하기 때문에 검색 속도의 향상을 가져올 수 있다.
인덱스의 구조
인덱스는 B-Tree (Balanced Tree)의 구조로 구성되어지는데, 구조적으로는 Binary Search Tree와 비슷하지만, 데이터 높이(층)를 자동으로 바로잡아주는 기능이 있습니다. Binary Search Tree의 경우 한쪽 Branch에만 데이터가 몰릴 수 있는데, 이 한계를 극복하기 위한 Balanced Tree를 사용한다.
위에서 보이는것 처럼, "ID=3"에 대한 정보를 찾는다면, 총 3번의 동작으로 데이터를 찾을 수 있다 - O(logN)
만약 선형 탐색일 경우 가장 윗줄인 ID=2부터 순차적으로 총 9번의 동작을 가진 후에 값을 찾을 수 있기때문 - O(N)
그렇다면 왜 하필 B-Tree를 사용할까?
- 탐색시간이 제일 빠른 "해시 테이블"을 사용하지 않는 이유
해시 테이블은 해시 값을 이용하여 저장된 메모리 공간에 한 번에 접근을 하기 때문에 O(1)이라는 시간 복잡도를 가진다.
하지만 이는 단 하나의 데이터를 탐색하는 시간에만 O(1)이 걸리는 것이며,
DB에서는 등호(=)뿐만 아니라 부등호(>,<)도 사용할 뿐더러 모든 값이 정렬되어있지 않으므로,
해시 테이블에서는 특정 기준보다 크거나 작은 값을 찾을 수 없다.
- 데이터 접근이 빠른 자료구조 "배열"을 사용하지 않는 이유
배열은 참조 포인터라는 개념이 없고, 모든 데이터가 메모리 상 차례대로 저장되어 있어 접근이 매우 빠르다.
참조가 없으니 당연히 탐색 속도로만 본다면 B-Tree보다 훨씬 빠르다.
뿐만 아니라, 해시 테이블과는 다르게 데이터들을 정렬 상태로 유지할 수 있으므로 부등호(< , >) 연산에도 문제가 없다.
하지만 배열이 B-Tree보다 빠른 것은 '탐색'뿐이다.
배열 내에서 데이터 저장, 삭제가 일어나는 순간 B-Tree보다 훨씬 비효율적인 성능이 발생하게 된다.
(삽입, 삭제의 경우 데이터를 한칸씩 이동하는 과정에서 평균 시간복잡도가 O(N)이 발생하기 때문)
인덱스의 관리
인덱스는 항상 최신의 데이터를 정렬된 상태로 유지해야 원하는 값을 빠르게 탐색할 수 있다.
그렇기 때문에 인덱스가 적용된 컬럼에 INSERT, UPDATE, DELETE가 수행된다면 계속 정렬을 해주어야 하고 그에 따른 부하가 발생한다.
이런 부하를 최소화하기 위해 인덱스는 데이터 삭제라는 개념에서 인덱스를 사용하지 않는다라는 작업으로 이를 대신한다.
- INSERT: 새로운 데이터에 대한 인덱스를 추가합니다.
- DELETE: 삭제하는 데이터의 인덱스를 사용하지 않는다는 작업을 진행합니다.
- UPDATE: 기존의 인덱스를 사용하지 않음 처리하고, 갱신된 데이터에 대해 인덱스를 추가합니다.
인덱스를 쓰는 이유 - 장점
인덱스의 가장 큰 특징으로는 데이터들이 정렬되어 있다는 점이다. 그렇기에 조건 검색이라는 영역에서 매우 큰 장점이 된다.
테이블을 Full Scan 할 필요가 없어지기 때문에 테이블을 조회하는 속도와 그에 따라 성능이 향상된다.
인덱스를 사용하면, SELECT 뿐만 아니라 UPDATE와 DELETE의 성능도 향상된다.
인덱스를 쓰는게 무조건 좋을까? - 단점
인덱스를 관리하기 위한 저장공간이 추가적으로 필요함 (DB의 약 10%에 해당)
인덱스를 관리하기 위해서 추가 작업이 별도로 필요
인덱스를 잘못되게 사용할 경우 성능이 오히려 저하되는 역효과가 발생함
인덱스의 가장 큰 문제점은 정렬된 상태를 계속 유지시켜줘야 한다는 점이다.
그렇기에 레코드 내에 데이터 값이 바뀌는 부분이라면 추가 작업이 발생하게 되는데,
INSERT, UPDATE, DELETE를 통해 데이터가 추가되거나 값이 바뀐다면 INDEX 테이블 내에 있는 값들을 다시 정렬을 해야 하므로
INDEX 테이블과 원본 테이블 이렇게 두 군데에 데이터 수정 작업해줘야 한다는 단점이 있다.
인덱스는 테이블의 전체 데이터 중에서 10~15% 이하의 데이터를 처리하는 경우에만 효율적이고
그 이상의 데이터를 처리할 땐 인덱스를 사용하지 않는 것이 더 낫다고 한다.
인덱스를 사용하면 좋은 경우
인덱스를 효율적으로 사용하려면 데이터의 분포도는 최대한으로 조건절에 호출 빈도는 자주 사용되는 컬럼을 인덱스로 생성하자.
컬럼에 인덱스를 걸 때, 내가 원하는 데이터를 선택하는 과정에서 최대한 많은 데이터가 걸러져야 성능이 좋을것이기 때문
카디널리티가 높을수록 인덱스 설정에 좋은 컬럼이다. (데이터 중복정도가 낮은)
- INSERT, UPDATE, DELETE가 자주 발생하지 않는 컬럼
- JOIN이나 WHERE 또는 ORDER BY에 자주 사용되는 컬럼
- 데이터의 중복도가 낮은 컬럼 (고유한 값 위주로)
결합 인덱스의 경우 컬럼 순서에 따라 엑세스 하는 범위가 달라지는데,
(중복도가 낮은 컬럼 ---- 중복도가 높은 컬럼) 순서대로 결합 인덱스를 구성해주는 게 좋다.
앞에서 필터링할 때 많이 걸러줄수록 뒤에서 탐색하는 범위가 줄어들기 때문임.
'데이터베이스' 카테고리의 다른 글
데이터베이스 Lock(락) (0) | 2022.05.09 |
---|---|
SQL과 NoSQL (0) | 2022.04.01 |