인덱스(Index)의 사전적 의미는 “색인, 책 속에 다루어진 중요한 단어나 용어를 독자가 쉽게 찾을 수 있도록 페이지를 밝혀 벌여 놓은 것.” 이란 뜻이다.
데이터베이스에서도 Index의 의미는 동일하게 이용된다.
대용량 데이터베이스 내에서 우리가 원하는 데이터를 빠르게 조회하기 위해 사용하는 것이 인덱스이다. 이는 Select 쿼리의 성능 향상이 인덱스의 목적이라고 할 수 있다.
인덱스는 데이터베이스의 테이블 내의 객체가 아닌 데이터베이스의 또다른 객체이다. 이는 인덱스를 사용하는 경우 테이블외에 추가적인 공간이 필요하다는 의미이다.
따라서, 인덱스는 조회 쿼리의 성능 향상을 가져오지만, 인덱스 정보에 관한 연산이 추가적으로 이뤄줘야 하기 때문에 DML(Insert, Update, Delete)에 있어서는 성능적으로 어느정도 희생을 하게된다.
- Insert : 테이블에 데이터를 Insert하면서 인덱스에도 정보를 저장해야한다.
- Delete: 데이터베이스 테이블 데이터의 삭제는 직접적으로 컬럼이 없어지지만, 인덱스는 사용하지 않는다는 체크를 한다. 이는 테이블의 실제 데이터 개수와 인덱스 값의 불일치기 발생할 수 있다.
- Update : Delete와 Insert의 문제점을 모두 갖는다. 사용하지 않는 인덱스를 체크하고, 인덱스에 업데이트 된 데이터를 추가한다.
가장 흔히 인덱스 검색에 사용되는 구조는 트리 구조이며, 흔히 사용되는 알고리즘은 B-Tree 알고리즘이다.
루트 페이지(노드)부터 리프 페이지(노드)까지 탐색을 시작하고, Clustered Index와 Non-Clustered Index의 차이에 따라 리프 페이지가 데이터 페이지인지 아니면 데이터가 있는 곳의 주소를 가리키는지로 구별된다.
Clustered Index
Clustered Index는 군집화된 인덱스라는 뜻이다. 즉 인덱스가 데이터를 포함하는 데이터와 무리를 이룬 인덱스이다.
이는 루트 페이지부터 데이터 검색을 시작하고, 리프 페이지가 검색하고자 하는 데이터를 담고 있는 데이터 페이지이다.
Clustered Index는 테이블 컬럼에 PK 제약조건을 걸어 생성하면 자동 생성되고 테이블 당 1개만 존재한다.
만약 Clustered Index가 2개가 존재하는 경우 어떤 데이터를 기준으로 정렬해야 하는지 모르기 때문에 반드시 1개만 존재한다.
예를 들어, “26” 컬럼의 데이터를 탐색해보자.
인덱스의 컬럼은 모두 정렬되어 있기 때문에, 루트 페이지의 17보다 26이 크므로 17의 주소인 102로 내려간다.
브랜치 페이지(102)의 17, 25중 26은 25보다 크기 때문에 25의 주소인 1005 페이지로 내려간다.
리프 페이지는 데이터 페이지이므로 데이터 페이지의 “26”컬럼인 “26, woi” 데이터를 조회한다.
Non-Clustered Index
Non-Clusuted Index는 Clusutered Index와 다르게 리프 페이지에 데이터가 존재하는 곳의 데이터 페이지 주소를 가지고 있다.
따라서, 데이터 페이지의 데이터가 정렬이 되어있지 않아도 사용할 수 있다. (인덱스의 컬럼은 정렬이 되어있다.)
Clustered Index와 다르게 여러 개의 컬럼에서 인덱스를 가질 수 있고, 해당 컬럼을 Unique 제약 조건을 걸어주면 자동으로 생성된다.
예를 들어, “5”라는 컬럼 데이터를 찾아보자.
인덱스 컬럼은 모두 정렬되어 있기 때문에 루트 페이지의 “1”의 주소인 101로 내려간다.
리프 페이지에 도달했으므로 “5”를 찾는다. “5”는 데이터 페이지의 1002#3이라는 주소를 가지고 있다. 이는 페이지 번호 + 오프셋으로 이뤄져있다.
데이터 페이지 주소인 1002#3은 1002번 페이지의 3번째 오프셋에 “5”라는 데이터가 있다는 뜻이다.
따라서, 1002번 페이지의 3번째 오프셋에서 “E, 5”라는 데이터를 조회한다.
카디널리티(Cardinality)
인덱스를 만들 컬럼은 카디널리티가 높은 것을 선택하는 것이 바람직하다.
카디널리티란 컬럼 데이터의 중복도와 관련이 있다. 즉 컬럼에 대해 Distinct를 걸어 나온 개수가 클 수록 카디널리티가 높다.
예를 들어 , 아래와 같은 데이터가 있다고 생각해보자.
ID | Sport | City |
1 | 농구 | 서울 |
2 | 농구 | 부산 |
3 | 야구 | 서울 |
4 | 축구 | 대구 |
5 | 야구 | 제주 |
6 | 축구 | 성남 |
7 | 야구 | 성남 |
8 | 축구 | 제주 |
ID는 고유한 값을 갖기 때문에 중복된 데이터가 없으므로 카디널리티 값이 높다.
Sports를 보자. 8개의 컬럼 중 “농구”, “축구”, “야구”라는 데이터가 중복된다. 즉 ID 보다 카디널리티가 낮다.
마지막으로 City를 보자. “서울”, “부산", “대구", “제주", “성남"이라는 데이터가 중복된다.
이 3개의 컬럼을 기준으로 카디널리티 값이 높은 순으로 나열해보자.
ID (중복되는 컬럼 없음 = 10) > City(중복되는 데이터 개수 5개) > Sports (중복되는 데이터 개수 3개) 순서이다.
COUNT(DISTINCT ID) FROM TABLE; # 10
COUNT(DISTINCT SPORTS) FROM TABLE; # 3
COUNT(DISTINCT CITY) FROM TABEL; # 5
예시는 데이터의 개수가 적지만, 실제 데이터베이스의 데이터는 대용량이고 이에 인덱스를 만들기 위해서는 카디널리티가 반드시 고려되어야 한다.
📄 References
[10분 테코톡] 🍫 찰리의 인덱싱 : https://www.youtube.com/watch?v=P5SZaTQnVCA
'Computer Science > DB' 카테고리의 다른 글
SQL과 관계형 모델 (정규화) (DB 스터디 3주차) (0) | 2022.09.28 |
---|---|
술어논리와 관계형 모델 (DB 스터디 2주차) (0) | 2022.09.21 |
SQL과 관계형 모델 (DB 스터디 1주차) (0) | 2022.09.16 |
반정규화 (De-Normalization) (0) | 2022.06.25 |
정규화 (Normalization) (0) | 2022.06.22 |