DB CRUD는 많이 그리고 잘 하는데, DB 튜닝의 꽃인 인덱스 기본 구조와 탐색 원리를 모르는 사람이 참 많다.
(나도 잘 모름)
인덱스 기본에 대해 간략히 기술하겠다.
DB 테이블에서 데이터를 찾는 방법은 두가지다.
- 디비 풀스캔
- 인덱스 사용
디비 풀스캔은 말그대로 멀티 블락 I/O(한번에 많은 데이터를 옮길 수 있는 자료)를 활용해 한번에 확! 읽어서 처리하는 방식이다.
디비 풀스캔이 절대적으로 안 좋다고 생각하는 사람들이 많은데 절대 그렇지 않다.
where 절에 속하는 범위가 많을때(1~2년 범위로 데이터 조회)는 그냥 풀스캔으로 한방에 처리하는게 훨씬 빠르고 좋다.
이유는 뭘까??
멀티블락I/O, 싱글블락I/O
DB 속도는 I/O와 관계가 있다. 즉 I/O가 작을수록 좋다. I/O를 간략히 설명하면 실행속도가 빠른 CPU 에서 상대적으로 느린 저장장치에 데이터를 요청할때 I/O가 발생하는데
CPU : "아... 데이터 저장장치 너무 느리네. 나는 빠르니깐 다른 프로세스에게 CPU 넘겨 주고 할거하고있을게 다 읽으면 인터럽트 걸어라.
I/O Device: "네! 알겠습니다. (데이터를 열심히 찾고) CPU님! 저 준비 됐습니다!"
I/O를 경박하게 말하면 위의 대화와 같다.
다시 본론으로 돌아와 풀스캔이 더 좋은 이유를 설명하겠다.
이유는 간단하다. 디비 풀스캔은 멀티 블락 I/O를 사용하기 때문에 I/O가 작다. 인덱스는 싱글 블락 I/O를 사용하기 때문에 I/O가 많다.
그래서 범위가 좁을땐 싱글 블락 I/O를 사용하는 인덱스가 훨씬 빠르지만(작은거 찾자고 풀스캔으로 다 읽으면 너무 느림) 범위가 많을땐 풀스캔이 오히려 유리하다.
인덱스 구조 및 원리
인덱스는 B트리 구조로 되어있다.
B 트리는 검색속도가 상당히 빠른 자료구조다(log n). 인덱스가 빠른 이유도 여기에 있다.
인덱스는 정렬된 데이터다. 이게 가장 중요하다. 정렬된 데이터. 그렇기 때문에 빨리 읽을 수 있다.
예를 살펴보자.
학생명부에서 시력이 1.0 ~1.5인 홍길동을 찾아보자 학생명부를 이름, 시력순으로 정렬했다면 아래와 같은 표가 된다.
※ 시력이 1.0 ~1.5인 홍길동은 2명이라고 가정
시력 | 학년 | |
이승우 | 1.5 | 4 |
이시연 | 1.2 | 3 |
탁유리 | 1.2 | 4 |
... | ... | ... |
홍길동 | 1.0 | 4 |
홍길동 | 1.5 | 4 |
이때는 이름순으로 정렬되어 있으니 정말 소량만 스캔하면 된다.
(이름 홍길동 찾아서 시력 읽기)
반면 시력과 이름순으로 정렬해 두었다면 똑같은 두명을 찾는데도 스캔량이 많이 늘어난다.
(시력이 1.0 가서 이름 쫙 스캔, 시력 1.5가서 이름 쫙 스캔)
시력 | 이름 | 학년 |
0.5 | 이승우 | 4 |
... | 3 | |
1.0 | 홍길동 | 4 |
... | ... | ... |
1.5 | 홍길동 | 4 |
1.5 | 홍길홍 | 4 |
인덱스 선두컬럼을 무엇으로 설정 했느냐에 따라 같은 인덱스라도 차이가 많이난다.
그럼 인덱스가 이름순으로 정렬된거 하나, 시력순으로 정렬된거 하나, 각각 있다면 어떤걸 선택해야 할까?
당연히 이름순이다. 이름찾고 시력찾는게 더 빠르니깐.
여기서 중요한 개념이 등장한다. 1. 인덱스 스캔 효율화, 2. 랜덤 액세스 최소화 두가지다.
인덱스 스캔 효율화는 학생 명부를 얼마나 효과적으로 빨리 읽느냐다.
※ 이름순으로 읽는게 더 효율적
랜덤 액세스 최소화는 학생명부에 없는 나머지 정보를 얻기 위해 직접 테이블을 액세스해서 비교하는 작업이다.
이때 바로 I/O가 발생한다.
시력순으로 정렬된 인덱스를 사용할 때 시력은 인덱스에서 알고 있으나 이름이 홍길동인지 확인해야 한다. 이때 테이블을 액세스(I/O) 해야한다.
물론 시력, 이름 두가지 다 인덱스에 있을때는 테이블 액세스가 발생하지 않는다.
그럼 두가지 인덱스 다 넣어서 만들면 되잖아?! 할 수 있겠지만 인생은 모든지 트레이드 오프다.
인덱스가 많아지면 초당 트랜잭션 횟수가 감소하고, 용량도 많이 차지한다.
(왜냐하면 insert 할때 인덱스 DB에도 정렬된 순서에 맞게 insert 해줘야 하니깐!)
결론 : 인덱스는 I/O 싸움이다. I/O는 최대한 적게!