본문 바로가기

DB

DB INDEX

첫 회사에 재직할 당시 은근 자주 들었던 얘기가 있다.

 

“뭐가 문제야?”

“이거 쿼리가 인덱스를 안 타는 것 같아요. 인덱스 설정이 안되어 있나?”

 

특정 데이터를 가져오기 위해 쿼리를 작성하는 사람들은 이 인덱스라는 것이 얼마나 중요한지 잘 알고 있을 것이다. 만약 DB 데이터가 적다면 인덱스는 반드시 필요하지 않을 수도 있다. 하지만 DB에 데이터가 어느정도 쌓이게 되면 인덱스는 더 이상 옵션이 아니라 필수가 된다.

 

오늘은 이러한 인덱스가 구체적으로 어떤 것이며 어떠한 방식으로 작동하는지 알아보고자 한다.

 


 

INDEX란

 

인덱스란 데이터베이스의 테이블에 대한 검색 속도를 향상시켜주는 자료구조이다. 테이블의 특정 컬럼(Column)에 인덱스를 생성하면, 해당 컬럼의 데이터를 정렬한 후 별도의 메모리 공간에 데이터의 물리적 주소와 함께 저장된다. 컬럼의 값과 물리적 주소를 (key, value)의 한 쌍으로 저장한다.

 

애초에 인덱스라는 단어 자체가 책 속의 내용을 쉽게 찾을 수 있도록 하는 색인을 의미한다는 걸 감안하면 DB에서의 인덱스도 동일한 목적을 지니고 있다는 걸 알 수 있다.


INDEX의 장점

 

1. 테이블을 조회하는 속도와 그에 따른 성능을 향상시킬 수 있다.

2. 그로 인해 전반적인 시스템의 부하를 줄일 수 있다.

 

인덱스가 없다면 테이블에서 원하는 데이터를 찾기 위해 모든 데이터를 검사하는 full table scan이 진행된다. 하지만 인덱스는 인덱스 데이터가 정렬 되어있기 때문에 조건에 맞는 데이터를 빠르게 찾을 수 있다.

 

 

INDEX의 단점

 

1. 인덱스를 관리하기 위한 추가 작업이 필요

2. 인덱스를 저장할 추가 저장 공간 필요

3. 잘못 사용할 경우 오히려 검색 성능 저하됨

 

인덱스는 항상 최신의 정렬상태를 유지해야 한다. 따라서 인덱스가 적용된 컬럼에 삽입(INSERT), 삭제(DELETE), 수정(UPDATE) 작업이 일어나면 다시 인덱스 데이터를 정렬해야 하는 추가 작업이 필요하다.

그리고 인덱스도 하나의 DB객체이다. 그렇기 때문에 DB 크기의 약 10% 정도의 저장공간을 필요로 한다. 따라서 인덱스를 무분별하게 추가할 경우 DB 저장공간이 낭비될 수 있다.

마지막으로 나이나 성별과 같이 값의 range가 적은 컬럼에 인덱스를 적용할 경우, 인덱스를 읽고 나서 다시 많은 데이터를 조회해야 하기 때문에 비효율적일 수 있다.

 

 

INDEX를 사용해야 하는 경우

 

1. 규모가 큰 테이블

2. 삽입(INSERT), 수정(UPDATE), 삭제(DELETE) 작업이 자주 발생하지 않는 컬럼

3. WHERE나 ORDER BY, JOIN 등이 자주 사용되는 컬럼

4. 데이터의 중복도가 낮은 컬럼


[ INDEX 자료구조 ]

 

B-TREE (Balanced-Tree)

 

B-Tree는 트리 자료구조의 일종으로 이진 트리를 확장해 하나의 노드가 가질 수 있는 자식 노드의 최대 숫자가 2보다 큰 트리 구조이다.

 

일반 Binary Search Tree의 한계

Binary Search Tree는 트리의 균형이 없을 때 최악의 시간 복잡도가 O(n) 이 나올 수 있다. 이러한 단점을 극복하고자 여러 자료구조가 나왔는데 B-Tree가 그 중 하나이다.

B-Tree는 트리 높이가 같고 자식 노드를 2개 이상 가질 수 있다는 특성이 있어 기본 데이터베이스 인덱스 구조로 활용되고 있다.

 

B-Tree 가 적용된 인덱스 구조 예시 - 페이지는 데이터가 저장되는 단위를 말한다.

 

위와 같은 자료구조 덕에 SELECT문의 속도가 향상된다는 것을 알 수 있다. 하지만 다음 작업들의 경우 이미 정렬된 B-Tree 구조가 바뀌어야 하기 때문에 오히려 성능 저하가 발생할 수 있다.

 

INSERT : 페이지에 새로운 데이터를 추가할 여유 공간이 없으면 페이지를 새로 생성하는 것 뿐만 아니라 기존의 데이터까지 다시 정렬해서 재분배하는 페이지 분할이 발생함

DELETE : 인덱스 데이터를 실제로 지우지 않고 사용 안함 표시를 함. 이로 인해 페이지 낭비와 인덱스 조각화 현상이 발생할 수 있다.

 

UPDATE : 인덱스에는 업데이트 개념이 없어서 DELETE 이후 INSERT가 진행된다.

 


 

[ INDEX의 종류 ]

 

CLUSTERED INDEX

 

Clustered Index는 테이블의 데이터를 지정된 컬럼에 대해 물리적으로 데이터를 재배열한다. 즉 Index를 생성할 때 데이터 페이지 전체를 다시 정렬한다.

 

ID 컬럼(분홍색)을 클러스터드 인덱스로 지정한 경우 - 하늘색으로 적힌 1000, 1001, 1002는 데이터 페이지의 주소를 의미한다.

이러한 클러스터드 인덱스의 특징은 다음과 같다.

 

  • 실제 데이터 자체가 정렬됨 
  • 테이블 당 1개만 존재 가능
  • 리프 페이지가 데이터 페이지
  • PRIMARY KEY 제약 조건 설정시 자동 생성됨

 

NON CLUSTERED INDEX

 

Non-Clustered Index는 물리적으로 데이터를 배열하지 않은 상태로 데이터 페이지가 구성된다. 즉 테이블의 데이터는 그대로 두고 지정된 컬럼에 대해 정렬시킨 인덱스를 만들 뿐이다.

NAME 컬럼(하늘색)을 넌 클러스터드 인덱스로 지정한 경우 - 하늘색 박스의 1002는 실제 데이터 페이지의 주소를 의미하고 빨간 박스의 #3은 3번째 데이터를 의미한다.

이러한 넌클러스터드 인덱스의 특징은 다음과 같다.

 

  • 실제 데이터 페이지는 어떠한 변경도 없다.
  • 별도의 인덱스 페이지를 생성한다 -> 추가 공간 필요
  • 테이블 당 여러 개 존재할 수 있다.
  • 리프 페이지에 실제 데이터 페이지 주소를 담고 있다.
  • UNIQUE 제약 조건 적용시 자동으로 생성된다.
  • 직접 INDEX를 생성하면 넌 클러스터드 인덱스가 생성된다.

 


Q&A

1. 인덱스가 적용된 테이블에서 UPDATE, DELETE 경우도 WHERE 절을 사용하면 빨라지나요?

  - WHERE 절을 통한 조회 성능이 향상되는 건 맞다. 하지만 UPDATE나 DELETE로 인한 추가 인덱스 작업이 성능을 저하시킨다.

 

2. HashTable을 인덱스 자료구조로 사용하지 않는 이유가 있나요?

  - '=' 연산이 아닌 '>'와 '<' 연산에 대해서는 Hash Table로 처리할 수 없다.

 

3. 클러스터드 인덱스와 넌 클러스터드 인덱스를 동시에 적용하면 어떻게 되나요?

  - 클러스터드 인덱스는 변함이 없으나 넌 클러스터드 인덱스는 리프 페이지에 실제 데이터 페이지 주소가 아닌 클러스터드 인덱스가 적용된 컬럼의 실제 값이 저장된다. (https://www.youtube.com/watch?v=edpYzFgHbqs 참고)

 


출처 : 
https://rebro.kr/167
https://mangkyu.tistory.com/96
https://www.youtube.com/watch?v=edpYzFgHbqs
https://www.youtube.com/watch?v=NkZ6r6z2pBg
https://velog.io/@gillog/SQL-Clustered-Index-Non-Clustered-Index

'DB' 카테고리의 다른 글

정규화(Normalization)  (2) 2024.10.07
DB Lock  (0) 2024.07.10
Transaction의 Isolation Level  (0) 2024.07.08
DB Transaction  (0) 2024.07.08