DB는 특정 데이터를 어떻게 찾아낼까요? 예를 들어, { id : interrupt } 라는 데이터를 찾으려고 하는데 어떻게 접근해야할까요?
사용자 : { id : interrupt } 의 데이터를 알려주세요.
해당 데이터를 찾기 위해서 DB는 디스크를 한번 다 훑어봐야합니다. (풀스캔) 하지만 매번 특정 데이터를 찾기 위해 풀 스캔을 하게 되면 시간이 너무 오래 걸리기 때문에 인덱스를 도입하게 되었습니다. 해당 데이터의 위치를 기록해 놓은 것이죠.
DB : { id : interrupt } 은 A 구역에 있습니다. A를 탐색 후 결과를 반환합니다.
이런 식으로 인덱스를 추가하게되면 DB의 조회 속도는 상상하지 못할 정도로 빨라집니다. 풀스캔을 하던 것이 한번에 가져오게 되는 것이니까요. 쿼리가 느리다고 생각되면, 먼저 인덱스가 잘 설정되었는 지 먼저 확인하는 것도 그 이유입니다.
하지만 인덱스도 단점이 존재합니다. 인덱스를 설정하는 것도 일종의 데이터를 만드는 작업이라 많이 만들게 되면 메모리를 잡아먹게 됩니다. 인덱스도 일종의 캐시처럼 잘 사용하는 인덱스만 메모리에 올려두고 사용합니다.
그리고 모든 데이터를 인덱스를 이용한다면 과연 빠를까요? 우리가 독서를 할 때 차례대로 읽지 색인을 찾아가면서 읽지는 않습니다. 인덱스를 이용한 접근은 랜덤 액세스이기 때문에 인덱스를 이용한 읽기는 어느 순간부터 풀스캔보다 느려질 수 밖에 없습니다.
그렇다면 인덱스로 접근할지, 그냥 접근할지 어떻게 정할까요? 인덱스로 접근하면 2초가 걸리고 그냥 접근하면 1초가 걸리면 당연히 그냥 접근하는 게 좋지 않을까요?
DB Optimizer는 오늘도 열일합니다.
그리고 DB에는 Optimizer라는 친구가 존재합니다. DB 명령을 받으면 이걸 어떻게 처리해야 가장 효율적인지를 계산하는 친구입니다.
예를 들어, FIND interrupt FROM A 라는 명령어가 있다고 해봅시다.
1. 사용자 : FIND interrupt FROM A
2. DB : A에서 interrupt를 찾으라는데?
3. Optimizer : 인덱스를 이용해볼까? 풀스캔을 해볼까? ...
(계산 중 ..)
인덱스를 사용하는 게 가장 빠르니까 이걸로 해야지!
위의 예시처럼 옵티마이저는 모든 방법을 계산해 최적인 방법으로 데이터를 찾아서 반환해줍니다. 모든 방법을 계산해야하기 때문에, 쿼리에 연관된 것들이 많아지면 경우의 수가 많아져 속도가 당연히 느려질 수 밖에 없습니다.
쿼리 하나에 연관된 테이블이 많아질 수록 그 경우의 수가 엄청나게 커지게 됩니다. 또 인덱스가 늘어나면 이 경우의 수가 또 늘어나게 됩니다.
그래서 어떻게 쿼리를 하느냐가 디비 성능을 크게 좌우합니다. 당연히 이런 계산을 매번하는 것은 컴퓨팅 리소스를 엄청나게 잡아먹는 짓입니다. 그래서 공유 풀이라는 곳에 이 계산들을 캐싱해놓습니다.
참고로 공유 풀 캐싱은 쿼리를 해싱해서 관리하기 때문에 대소문자를 구분합니다. SELECT a FROM b 와 select a from b 는 다른 쿼리라고 인지하는 것이죠. 따라서 쿼리를 작성할 때는 항상 대문자로만(혹은 소문자로만) 작성하는 것이 좋습니다.
요약하자면,
DB Index는 쿼리 속도를 향상시킬 수 있는 아주 중요한 요소이다.
하지만 많이 만들면 오히려 쿼리 속도가 느려질 수 있다.
DB 관련된 지식은 끝도 없습니다. DB의 어떤 것부터 공부해야할지도 모르겠고, 당장 내게 필요한 지식인지도 모르겠는 것이 당연합니다. 인덱스가 내부적으로 어떤 자료구조를 사용하고, 어떤 알고리즘으로 캐싱이 되고 하는 지를 다 알기란 힘든 일입니다.
물론 알면 좋죠. 다다익선입니다
하지만 더 중요한 요소들이 있는데 DB를 계속 파고 들기란 어렵습니다. 그래서 DB가 대충이나마 어떻게 동작하는 지를 이해할 수 있었으면 좋겠다 싶어서 최근에 정리를 조금이나마 해봤습니다.
더 많은 정보가 궁금하다면 뉴스레터를 읽어주세요. https://maily.so/interrupt