본문으로 바로가기

20

데이터베이스 인덱스

책 뒤의 색인 한 장이 책 전체를 읽는 일을 없애준다

먼저 보면 좋은 강의: 웹 요청의 해부, 지연 시간과 처리량, SQL과 NoSQL

단계별로 보기

스페이스바로 재생/정지, 좌우 화살표로 단계 이동, R로 처음으로 돌아갑니다.

대기 중1 / 4 단계 — 인덱스 없이 — 매번 처음부터 끝까지

인덱스가 없습니다. 조회 하나마다 데이터베이스가 데이터를 전부 훑습니다. 질의 하나에 원래 5밀리초면 될 일이 40밀리초가 듭니다. 여덟 배입니다. 데이터베이스는 고장난 게 아닙니다. 시키는 대로 성실히 다 읽고 있을 뿐입니다.

유입 요청초당 400건
처리 완료초당 200건

이 강의를 마치면

  • 인덱스가 없을 때 데이터베이스가 데이터를 처음부터 끝까지 훑는다는 것을 설명한다.
  • 인덱스가 질의 시간을 몇 배로 줄이는지 시뮬레이션으로 관찰한다.
  • 인덱스의 대가(저장 공간과 쓰기 속도)가 무엇인지 설명한다.
  • 느린 데이터베이스에 서버를 더 붙이는 것이 왜 해결책이 아닌지 판단한다.

500쪽짜리 책에서 한 단어 찾기

두꺼운 전문서적에서 "환율"이라는 단어가 나오는 곳을 찾아야 한다고 합시다. 방법은 두 가지입니다.

  1. 1쪽부터 500쪽까지 넘기면서 눈으로 훑는다.
  2. 책 뒤 색인에서 "환율"을 찾아 "312쪽"을 확인하고 바로 펼친다.

누구도 1번을 고르지 않습니다. 그런데 인덱스가 없는 데이터베이스는 항상 1번을 합니다. 다른 방법이 없기 때문입니다.

데이터베이스는 성실할 뿐이다

"이메일이 kim@example.com인 사용자를 찾아줘"라고 요청하면, 데이터베이스는 이메일 목록이 어떻게 생겼는지 모릅니다. 그래서 1번 행부터 마지막 행까지 전부 꺼내서 하나씩 비교합니다. 이걸 전체 스캔(full scan)이라고 합니다.

사용자가 100명이면 100번 비교하고 끝입니다. 아무 문제 없습니다. 사용자가 1,000만 명이면 1,000만 번 비교합니다. 그리고 이 일을 요청 하나마다 반복합니다.

사용자 1,000만 명 × 초당 100건의 조회
= 초당 10억 번의 비교

이게 바로 "어제까지 멀쩡하던 서비스가 갑자기 느려진" 사건의 가장 흔한 원인입니다. 코드는 한 줄도 바뀌지 않았습니다. 데이터가 늘어났을 뿐입니다.

인덱스 = 책 뒤의 색인

인덱스는 데이터베이스가 미리 만들어 두는 색인입니다. 이메일에 인덱스를 걸면 데이터베이스는 이메일을 정렬된 별도 목록으로 따로 관리합니다.

정렬되어 있으면 전부 볼 필요가 없습니다. 사전에서 단어를 찾을 때 첫 장부터 넘기지 않는 것과 같습니다. 가운데를 펼쳐 보고, 찾는 게 앞이면 앞쪽 절반만, 뒤면 뒤쪽 절반만 보면 됩니다. 이걸 반복하면

데이터 건수전체 스캔인덱스 사용
1,000건1,000번 비교약 10번
100만 건100만 번 비교약 20번
10억 건10억 번 비교약 30번

데이터가 100만 배 늘어나는 동안 인덱스 쪽 작업은 3배밖에 늘지 않습니다. 이 표가 인덱스의 전부입니다.

그러면 전부 걸면 되지 않나

아닙니다. 인덱스에는 두 가지 대가가 있습니다.

첫째, 자리를 차지합니다. 색인도 종이를 씁니다. 인덱스는 원본과 별개로 저장되므로 데이터베이스가 그만큼 커집니다.

둘째, 고칠 때 같이 고쳐야 합니다. 이게 더 중요합니다. 사용자 한 명을 추가하면 원본에 한 줄 넣고 끝이 아니라, 인덱스에도 올바른 자리를 찾아 끼워 넣어야 합니다. 인덱스가 5개면 5번 해야 합니다.

즉 인덱스는 읽기를 빠르게 하는 대신 쓰기를 느리게 합니다. 읽기가 압도적으로 많은 대부분의 서비스에서는 남는 장사지만, 공짜는 아닙니다.

서버를 늘리면 안 되나요

안 됩니다. 그리고 이게 이 강의에서 가장 중요한 부분입니다.

서버를 10대로 늘리면 데이터베이스에 초당 10배 많은 전체 스캔을 요청하게 됩니다. 책을 처음부터 읽는 사람이 열 명으로 늘었을 뿐, 책은 여전히 한 권입니다. 오히려 더 빨리 무너집니다.

느린 질의는 질의를 고쳐야 합니다. 아래 과제에서 직접 확인해 보세요. 인덱스 스위치 하나가 서버 여러 대보다 낫습니다.

이 강의가 단순화한 것

교육용 모형은 언제나 무언가를 생략합니다. 무엇을 생략했는지 아는 것도 학습의 일부입니다.

전제한 것

  • 인덱스 유무를 켜고 끄는 스위치 하나로 단순화하고, 그 효과를 '질의 시간 × 8배'라는 고정 배수로 표현한다. 실제 배수는 데이터 건수에 따라 달라지며 수백 배가 되기도 한다.
  • 인덱스가 있으면 모든 질의가 인덱스를 탄다고 가정한다. 실제로는 질의의 조건이 인덱스와 맞아야 하고, 데이터베이스의 질의 계획기가 인덱스를 쓸지 스스로 판단한다.
  • 이 강의의 데이터 건수는 시간이 지나도 변하지 않는다. 인덱스가 중요해지는 진짜 이유는 데이터가 계속 늘어난다는 점이다.
  • 인덱스 유지 비용(쓰기가 느려지는 정도)은 쓰기 비용 배수라는 하나의 값으로 뭉뚱그린다.

다루지 않은 것

  • B-트리, LSM-트리 등 인덱스의 실제 자료구조
  • 복합 인덱스와 컬럼 순서, 커버링 인덱스
  • 질의 계획기(EXPLAIN)와 통계 기반 최적화
  • 카디널리티가 낮은 컬럼에서 인덱스가 오히려 쓸모없어지는 경우

더 읽을거리: Use The Index, Luke! — SQL 인덱스 입문

이제 직접 만들어 보세요

읽어서 아는 것과 만들어서 아는 것은 다릅니다. 컴포넌트를 배치하고 트래픽을 흘려서 실제로 동작하는지 확인해 보세요.

실습 과제 열기

이 강의에 물어보기

하루 5번

이 강의 본문만 근거로 답합니다. 강의에 없는 내용은 지어내지 않습니다.