Index?
클러스터드/넌클러스터드 인덱스가 뭔지 알아보기 전에 인덱스에 대해 간단히 정리하고 가보자.
인덱스는 데이터베이스에서 내가 원하는 값을 가진 데이터를 빠르게 찾게 해주는 자료구조이다.
보통 검색을 위해 사용하는 알고리즘에는 대표적으로 이진 탐색, 해시 탐색 등이 있는데 데이터베이스의 특성상 딱 원하는 값을 찾는 where age = 25
와 같은 구문뿐만 아니라 where age > 25
등의 범위를 조건으로 달아주는 구문도 자주 요청되기 때문에 해시 알고리즘을 적용하기에는 한계가 있어 대부분의 인덱스는 트리를 활용한 탐색을 사용하며 B-Tree (Balanced Tree) 자료구조를 사용한다.
그럼 인덱스는 탐색을 빠르게 해주니까 모든 열에 인덱스를 걸어주면 되는거 아닌가요?
라고 생각하기 쉽지만 그렇지 않다. __
인덱스는 SELECT의 성능을 올려주는 반면에 UPDATE, INSERT, DELETE 요청이 들어오면 부하가 발생하게 된다.
인덱스를 씌운 열에 새로운 데이터가 들어오거나 값이 바뀌게 되면 저장된 데이터의 배열을 다시 바꾸어 주어야 하기 때문이다.
그렇기 때문에 인덱스는 마구잡이로 생성해 주면 안 된다.
그러면 어떤 열에 인덱스를 생성해 주어야 하나요?
위에서 언급한 것처럼 인덱스는 SELECT와 UPDATE, DELETE, INSERT 성능의 등가교환이기 때문에 신중히 달아주어야 하는데 이 고민 해결에 도움이 될 몇 가지 좋은 기준들이 있다.
- 카디널리티(Cardinality)가 높은 컬럼에 달아주어라
- 카디널리티란 데이터의 유니크한 정도를 의미한다. 카디널리티가 높다는 것은 컬럼이 갖는 값의 중복도가 낮다는 의미이고 이는 낮은 선택도로 연결되어 인덱스를 생성하기에 적합한 조건을 갖추게 된다.
- 조회 활용도가 높은 컬럼에 달아주어라
WHERE
속의 조건으로 많이 활용되는지!
인덱스를 달아주어도WHERE
절에서 쓰이지 않으면 인덱스를 활용하여 탐색을 하지 않는다.
- 삽입, 변경, 삭제가 자주 발생하지 않는 컬럼에 달아주어라
- 인덱스는 삽입, 변경, 삭제가 발생할 때 성능이 떨어지기 때문에 이 작업이 잘 이루어지지 않는 컬럼에 걸어주어야 한다.
- 내 생각으로는 삽입이 없는 데이터베이스는 상상하기 힘들다.
삽입이 불가피하다면닉네임
이나직업
과 같은 컬럼보다는이름
,주민번호
와 같이 불변성이 더 높은 컬럼을 우선적으로 고려해 보면 되겠다.
Clustered Index
Cluster?
Cluster는 무리
, 무리를 이루다
와 같은 사전적 의미를 갖고 있습니다.
그렇기 때문에 실제 데이터와 인덱스가 하나의 무리를 이룬다
, 즉 실제 데이터가 저장된 공간을 정렬하여 인덱스를 만드는 것이 클러스터드 인덱스이고 실제 데이터와 무리를 이루지 않는
, 실제 데이터와 무관하게 인덱스를 생성하는 것을 넌클러스터드 인덱스라고 보면 됩니다. 이러한 차이 때문에 클러스터드 인덱스와 넌클러스터드 인덱스 사이에 장단점과 차이점이 발생하게 됩니다.
먼저 클러스터드 인덱스는 테이블에서 데이터가 물리적으로 저장된 공간의 순서를 결정짓습니다. 어떤 열로 정렬을 하냐에 따라 데이터들의 배열이 달라지기 때문에 한 테이블에는 하나의 컬럼에 대한 클러스터드 인덱스를 만들 수 있습니다.
SQL 서버에서는 테이블을 생성할 때 프라이머리키를 설정해 주면 자동적으로 해당 열에 대한 클러스터 인덱스를 생성합니다.
만약 기존 테이블에 클러스터 인덱스가 존재하지 않는 경우 하나의 컬럼에 unique + not null을 설정해 주면 해당 열에 대한 클러스터 인덱스를 생성합니다. 또한 하나의 열에 대해 클러스터 인덱스를 생성하는 명령을 통해서도 생성이 가능합니다.
Non-Clustered Indexes
반대로 넌클러스터드 인덱스는 실제 테이블에서 데이터가 저장되는 공간에 관여를 하지 않습니다. 대신에 추가적인 공간을 생성하여 넌클러스터드 인덱스와 테이블의 데이터를 저장합니다.
이러한 점 때문에 클러스터 인덱스와는 달리 한 테이블에 여러 개의 넌클러스터드 인덱스를 생성할 수 있는 것이죠.
클러스터드 인덱스와는 달리 리프 노드(리프 테이블)에 데이터 자체가 아닌 해당 데이터의 주소값을 저장합니다. 그렇기 때문에 넌클러스터드 인덱스는 주소값을 구한 후 한 번의 방문 과정을 더 거쳐야 하므로 클러스터드 인덱스보다 SELECT 성능이 살짝 느립니다.
대신 수정, 삭제, 삽입 시 클러스터드 인덱스는 실제 데이터 공간을 활용하므로 B-Tree의 높이 값을 유지하기 위한 작업이 수행되어 더 불리하다고 할 수 있죠.
넌클러스터드 인덱스도 클러스터드 인덱스와 마찬가지로 CREATE NONCLUSTERED INDEX
키워드를 사용하여 생성할 수 있으며 unique
키워드가 붙으면 자동으로 생성됩니다.
결론
- 하나의 테이블에는 하나의 클러스터드 인덱스만 만들 수 있다.
반대로 넌클러스터드 인덱스는 여러 개 만들 수 있음! - 클러스터드 인덱스는 실제 데이터가 존재하는 테이블을 정렬하는 것만으로 동작하기 때문에 추가적인 메모리 공간을 필요로 하지 않는다.
반대로 넌클러스터드 인덱스들은 추가적인 공간이 필요! - SELECT 문의 성능은 클러스터드 인덱스가 조금 더 빠르다!
추가적인 방문 단계 없이 데이터를 찾기 때문!
정도로 정리할 수 있겠다…
개인적인 이해로는
1
2
3
4
1. 조회 성능을 높이기 위해 인덱스를 도입해야지! => 여러 개의 인덱스(현재 넌클러스터드 인덱스라고 불리는)를 만듦
2. 어? 근데 이거 실제 데이터 공간에 접근해서 정렬해 주면 기존 인덱스 방법보다 조회도 조금 더 빠르고 메모리도 아낄 수 있겠는데? 대신 하나밖에 못 만들어!
3. 그럼 가장 효율이 좋을 것 같은 열을 해당 인덱스로 만들자!
4. 만들고 보니 두 가지의 인덱스가 생겼네? 그럼 우리 이거 이름을 클러스터드 / 넌클러스터드 인덱스라고 하자!
와 같은 흐름으로 이해를 하고 있다. 처음부터 클러스터드/넌클러스터드 딱 딱 나눠져서 생겼다기보단 이런 식의 과정 속에서 두 단어가 생기지 않았을까.. 하는 내 생각이다 ㅇㅇ…
아무튼 오늘 클러스터드 인덱스와 넌클러스터드 인덱스가 무엇이며 어떤 점이 다른지에 대해 알아보았다. 이렇게 정리하고 나니 기억에 오래 남을 것 같다..
전에는 아무 생각 없이 인덱스 쓰면 빨라져요!
라는 말만 듣고 뭔지도 모른 채 그냥 집어넣었는데 뭔지 알고 나니까 어떻게 더 효율적으로 사용할 수 있을지, 어떤 점을 조심해야 하는지 한 번 더 생각하고 사용할 수 있을 것 같다.