인덱스

Database Index

개념

특정 값을 빨리 찾으려고 미리 정렬해 둔 별도 자료로, 느려진 조회를 손볼 때 가장 먼저 꺼내는 수단입니다.

등장 배경

인덱스가 없으면 데이터베이스는 찾는 값이 어디 있는지 모릅니다. 그래서 첫 줄부터 마지막 줄까지 전부 읽어 보며 조건에 맞는지 하나씩 확인합니다. 줄이 서른 개일 때는 이 방식이 티도 나지 않습니다. 문제는 줄이 쌓인 뒤에 생깁니다.

페이지덱 초창기에 문서 표는 3만 줄이었고 검색은 0.1초 만에 끝났습니다. 2년 뒤 200만 줄이 되자 같은 검색이 6초를 넘겼습니다. 코드는 한 줄도 바뀌지 않았고 서버도 그대로였는데, 읽어야 할 줄이 예순 배가 됐을 뿐입니다. 고객센터에는 "검색 누르고 한참 기다린다" 는 문의가 쌓였습니다.

이때 떠오르는 해법은 대개 둘입니다. 데이터를 줄이거나 서버를 키우는 것입니다. 앞은 지울 수 있는 데이터가 없어서 못 하고, 뒤는 돈이 들면서도 줄이 열 배 더 쌓이면 원점입니다. 인덱스는 세 번째 길입니다. 데이터도 서버도 그대로 두고, 찾아가는 길만 바꿉니다.

작동 방식

찾을 값을 미리 정렬해 놓고 그 값이 몇 번째 줄에 있는지를 함께 적어 둔 자료를 따로 만들어 두는 방식입니다. 책 뒤에 붙은 찾아보기와 같습니다. 본문을 처음부터 넘기는 대신 찾아보기에서 낱말을 찾고 거기 적힌 쪽수로 바로 건너뜁니다.

만드는 순서는 셋입니다.

  1. 어느 칸에 걸지 고릅니다. 테이블은 행과 열로 데이터를 담는 저장 단위이고, 열 하나가 이메일이나 가입일 같은 항목 하나입니다. 조건으로 자주 쓰이는 열을 고릅니다.
  2. 데이터베이스가 그 열의 값을 정렬한 자료를 만들고, 값마다 원래 행이 어디 있는지를 붙여 둡니다.
  3. 조회가 들어오면 이 정렬된 자료에서 범위를 반씩 좁혀 가며 값을 찾고, 거기 적힌 위치의 행만 읽습니다.

효과는 줄이 많을수록 커집니다. 200만 줄을 전부 훑으면 200만 번 비교하지만, 정렬된 자료에서 반씩 좁히면 스무 번 남짓이면 닿습니다. 6초가 0.01초가 되는 차이가 여기서 나옵니다.

대가도 있습니다. 새 줄이 들어오거나 값이 바뀌면 본문뿐 아니라 인덱스도 함께 고쳐야 합니다. 한 표에 인덱스를 열 개 걸어 두면 줄 하나를 쓸 때마다 열한 군데를 고칩니다. 저장 공간도 따로 먹습니다. 조회는 빨라지고 쓰기는 느려지는 맞바꿈이라, 실제로 조건에 자주 오르는 열에만 겁니다.

걸어 두고도 안 쓰이는 경우가 있습니다. 값의 종류가 너무 적으면 효과가 없습니다. 참과 거짓 두 종류뿐인 열은 인덱스를 타도 절반을 읽어야 해서 전부 읽는 것과 별 차이가 없습니다. 조건에서 값을 가공해도 못 씁니다. 정렬해 둔 것은 원래 값이라 가공한 결과는 이 자료에 없기 때문입니다.

쓰이는 곳

인덱스가 붙는 자리는 대체로 넷입니다.

  1. 조건 검색 — SQL로 조회할 때 조건 자리에 오르는 열입니다. 이메일로 회원을 찾거나 문서 제목으로 검색하는 화면이 여기 해당합니다.
  2. 표끼리 잇는 자리 — 외래 키는 다른 표의 행을 가리키는 열인데, 주문 목록에 회원 이름을 붙이려면 이 열로 두 표를 맞춰야 합니다. 맞추는 쪽 열에 인덱스가 없으면 표 하나를 통째로 훑습니다.
  3. 정렬과 기간 조회 — 최신순 스무 건을 보여 주는 목록이나 지난달 가입자를 뽑는 조회입니다. 정렬해 둔 자료를 그대로 쓰므로 순서대로 필요한 만큼만 읽고 멈춥니다.
  4. 중복 금지 — 같은 이메일로 두 번 가입하는 것을 막는 장치도 인덱스로 만듭니다. 기본 키처럼 행 하나를 고유하게 가리키는 열에는 대개 인덱스가 자동으로 붙습니다.

반대로 안 거는 자리도 분명합니다. 줄이 몇백 개뿐인 설정 표는 전부 읽어도 순식간이고, 쓰기만 쏟아지는 기록 표는 인덱스가 오히려 짐입니다.

찾기 어려운 쪽은 ORM을 쓸 때입니다. ORM 은 코드의 객체와 표를 이어 주는 도구라서 조회문을 직접 쓰지 않는데, 그러면 어떤 열이 조건에 오르는지가 코드만 봐서는 드러나지 않습니다. 이때는 데이터베이스가 남기는 느린 조회 기록을 보고 실제로 나간 문장을 확인합니다.

실무 용례

"이 조회 느린데 인덱스를 안 타는 것 같아요."

인덱스가 걸려 있는데도 데이터베이스가 그걸 쓰지 않고 표 전체를 읽고 있다는 뜻입니다.

"그 열에 인덱스 걸면 조회는 빨라지는데 쓰기가 느려져요."

이득과 대가를 같이 보자는 말이고, 대개 쓰기가 얼마나 잦은 표인지 확인하자는 제안으로 이어집니다.

"일단 인덱스부터 걸어 보고 다시 재 봅시다."

구조를 뜯어고치기 전에 가장 싸고 빨리 되돌릴 수 있는 수단을 먼저 쓰자는 뜻입니다.

페이지덱에서 검색이 6초까지 늘어졌을 때 태오가 한 일이 이것입니다. 느린 조회 기록을 열어 보니 문서 표를 200만 줄 통째로 읽는 문장이 하루 4만 번 나가고 있었습니다. 제목 열에 인덱스를 걸자 같은 문장이 0.2초로 떨어졌습니다. 고친 것은 코드가 아니라 표의 구조뿐이었습니다.

작업은 새벽에 했습니다. 이미 쌓인 200만 줄을 정렬해 자료를 만드는 동안 그 표에 쓰기가 밀릴 수 있어서입니다. 지현에게는 "조회가 느린 건 오늘 밤에 풀리고, 문서 저장이 잠깐 느려질 수 있다" 고 미리 알렸습니다.

흔한 오해

인덱스를 많이 걸수록 좋다고 생각하기 쉽습니다. 조회가 빨라지는 걸 한 번 보고 나면 다른 열에도 걸어 두고 싶어지고, 거는 데 드는 노력이 한 줄이라 말리는 사람도 없습니다. 하지만 인덱스는 저장 공간을 먹고 쓰기마다 함께 갱신되는 자료입니다. 쓰지 않는 인덱스를 열 개쯤 쌓아 두면 조회는 그대로인데 저장과 수정만 눈에 띄게 느려지고, 몇 달 뒤 "쓰기가 왜 이렇게 느리냐" 는 질문에 아무도 답하지 못하는 상태가 됩니다.

느린 조회는 전부 인덱스로 풀린다는 생각도 자주 봅니다. 한 번 효과를 크게 본 수단이라 다음에도 먼저 손이 갑니다. 그런데 N+1 문제처럼 조회 한 번이 느린 게 아니라 조회가 101번 나가는 상황은 인덱스로 줄지 않습니다. 101번이 각각 빨라질 뿐 횟수는 그대로라서, 인덱스를 걸어도 화면은 여전히 느립니다. 이런 상황에서 인덱스만 계속 추가하면 원인을 못 찾은 채 쓰기 성능만 깎아 먹습니다.

같이 보면 좋은 페이지

  • 데이터베이스

    인덱스가 어느 시스템 안에서 쓰이는 장치인지 먼저 봅니다

  • N+1 문제

    인덱스로는 풀리지 않는 다른 종류의 느림입니다

마지막 업데이트 2026-09-16