DataBase

[DataBase] 인덱스

펭귄코기 2022. 11. 24. 21:04

1. 인덱스란?

데이터를 빠르게 찾을 수 있는 하나의 장치이다

예를들면 책의 마지막 장에 있는 찾아보기를 떠올리면 된다

 

책의 본문이 있고 그 본문 안에 내가 찾고자 하는 항목을 찾아보기를 통해 빠르게 찾는다

 

이와 같이 인덱스를 설정하면 테이블 안에 내가 찾고자 하는 데이터를 빠르게 찾을 수 있다

 

2. B-트리

인덱스는 보통 B-트리 라는 자료구조로 이루어져 있다

 

이는 루프 노드, 리프 노드, 그리고 그 사이의 브랜치 노드로 나뉜다

 

1) 루프 노드와 리프 노드를 기반하는 예시

 

예를 들어 E를 찾는다고 하자 이때 전체 테이블을 다 돌면서 찾는것이 아니라

E가 있을 법한 리프노드로 들어가서 탐색을하면 E를 찾기 더 쉽고 빨라진다

 

즉 전체를 돌려면 A부터 시작해서 E까지 도달하려면 5번이 걸린다면

D부터 시작하는 인덱스부터 찾으면 2번만에 도달하게된다

 

2) 트리 탐색 예시

 

트리 탐색은 맨 위 루트 노드 부터 탐색이 일어나면

브랜치노드 를거쳐 리프노드에 도달하는 탐색 법이다

 

57을 찾는다고 하면 57보다 같거나 클때까지 이동을 하는데

예를들어 57을 찾는다고 했을때 39는 57보다 작으니 오른쪽으로 이동한다

그리고 83을 만나서 57보다 크니 왼쪽으로 내려간다

46은 57보다 작으니 오른쪽으로 이동 이런식으로 가다가 57을 만나면

57이 가리키는 데이터 포인터를 통해 값을 반환한다

 

3. 인덱스가 효율적인 이유와 대수확장성

인덱스가 효율적인 이유는 효율적인 단계를 거쳐 모든 요소에 접근할 수 있는

균형잡힌 트리 구조와 트리 깊이의 대수확장성 때문이다

 

여기서 대수확장성이란 트리 깊이가 리프 노드 수에 비해

매우 느리게 성장하는것을 의미한다

기본적으로 인덱스가 한 깊이씩 증가 할 때마다

최대 인덱스 항목의 수는 4배씩 증가한다

 

트리 깊이 인덱스 항목의 수
3 64
4 256
5 1024
6 4096
7 16384
8 65536
9 262144
10 1048576

 

위에서 보듯이 트리 깊이 10개짜리로 100만개의 레코드를 검색할 수 있다

실제 인덱스는 이보다 더 효율적이기에 인덱스가 효율적이라 말 할  수 있다

 

4. 인덱스 만드는 방법

인덱스 만드는 방법은 데이터베이스마다 다르다

RDB, NoSQL 대표적인 MySQL과 MongoDB로 알아보자

 

1) MySQL

MySQL 의 Index 는 클러스터드 인덱스(Clustered Index) 와 논클러스터드 인덱스(Non-Clustered Index)

또는 세컨더리 인덱스(Secondary Index) 라고 하는 보조 인덱스가 존재한다

 

먼저 이 둘을 책과 비유하자면 클러스터드 인덱스의 경우 '영어 사전'과 같은 책이고

보조 인덱스의 경우 책의 맨 뒷장에 '찾아보기' 가 존재하는 일반적인 책과 같다

 

클러스터 인덱스 (Clustered Index)

- 테이블당 하나를 설정할 수 있다

- primary key 옵션으로 기본키로 만들면 클러스터형 인덱스를 생성할 수 있다

- 기본키가 아닌 unique not null 옵션으로도 만들 수 있다

 

앞서 클러스터드 인덱스는 '영어 사전' 과 같다고 표현했다
영어사전은 일반적인 책과 같이 '찾아보기' 페이지가 존재하지 않는다
다만 목차가 존재하며 목차는 A~Z 까지 단어가 순서대로 정렬되어 있어 목차가 곧 해당 단어를 나타낸다

즉, 목차 자체가 책의 내용과 같다는 것이다 == 내용 자체가 인덱스이다

 

클러스터드 인덱스는 이와 같이 동작한다
데이터베이스 테이블의 데이터(행 데이터)는 클러스터드 인덱스를 기준으로 자동 정렬되어진다는 것이다 (MySQL 의 경우 오름 차순 정렬이 되어짐)
그리고 클러스터드 인덱스는 테이블당 1개만 생성할 수 있으며 중복된 값을 가질 수 없다
앞선 특징들로 미루어볼 때 바로 Primary Key(PK) 가 떠오르는 사람들이 있을 수도 있을 것 같다
우리가 테이블의 특정 컬럼에 PK 를 생성하는 순간 자동으로 해당 컬럼에 클러스터드 인덱스가 생성된다
즉, "특정 컬럼을 PK 로 지정한다" 라는 것은

곧 "해당 컬럼에 클러스터드 인덱스가 생성된다" 라는 것으로 기억할 수 있다

 

넌클러스터 인덱스(Non-Clustered Index)

- create index 명령어를 기반으로 만들 수 있다

- 보조 인덱스로 여러 개의 필드 값을 기반으로 쿼리를 많이 보낼때 생성한다

 

보조 인덱스는 일반적인 책의 '찾아보기' 페이지와 같다고 표현했다
이게 무슨 말이냐면 우리가 원하는 정보를 검색하기 위해 '찾아보기' 페이지를 살펴본 후에

해당 정보 옆에 표시된 페이지로 다시 이동해야 원하는 정보를 찾아낼 수 있다는 것이다
보조 인덱스는 이와 같이 동작하게 된다
그리고 '찾아보기' 페이지에는 많은 종류의 정보가 표시돼있는데

이와 같이 보조 인덱스는 여러 개 생성될 수 있다

 

하나의 인덱스만 생성하는것이면 클러스터형 인덱스가 더 성능이 좋다

즉 age라는 하나의 필드만으로 쿼리를 보낸다면 클러스터형 인덱스

age, name, email 등 다양한 필드를 기반으로 쿼리를 보내면 세컨더리 인덱스

 

2) MongoDB

MongoDB의 경우 도큐먼트를 만들면 자동으로 ObjectID가 형성된다

그리고 이 키가 기본키로 설정된다

세컨더리키도 부가적으로 설정해서 기본키와 세컨더리키를 같이 쓰는

복합 인덱스를 설정할 수 있다

 

5. 인덱스 최적화 기법

인덱스를 사용할 때 고려할 점을 적어보겠다

1) 중복 인덱싱 피하기

키로 설정된 곳에 인덱싱 추가하지 않는다

 

2) 인덱스 최소화

인덱스 역시 사본 형태로 저장된 데이터라

하드웨어 자원을 소모, 성능을 저하 시킨다

 

3) WHERE, ORDER BY, GROUP BY 절에는 인덱스 지정

서버 결과를 fetch 하는데 더 빠르게 하는 것을 도와준다 (정렬에도 도움)

 

4) 인덱스 중복 데이터 확인

카운트 비율을 활용해 index uniqueness 비율을 확인한다

평균 90% 이상으로 유지한다

 

SELECT (COUNT(DISTINCT indexed_column)/COUNT(*)) * 100 FROM some_table;

 

5) 문자열을 CRC32로 인덱싱

회원 아이디, 회원 이메일 등은 CRC32컬럼으로 select 한다

 

SELECT * FROM tables
WHERE email_crc = crc32('seongman@seongman.com') AND email = 'seongman@seongman.com';