조회가 느리면 인덱스부터 걸고 보는 개발자에게
by 그릿 | GROWTH_ESSAY | 2026-11-05
#백엔드 #데이터베이스 #성능최적화 #멘토링멘토링을 하면서 성능 최적화 질문을 받을 때마다 가장 먼저 묻는 질문이 있습니다. "최근에 추가한 인덱스가 실제로 쿼리 시간을 얼마나 줄였나요?" 열 명 중 여덟 명은 말문이 막힙니다. 조회가 3초 넘게 걸리길래 조건절에 들어간 컬럼에 그냥 인덱스를 걸었다고 답합니다.
그런데 정말 인덱스만 걸면 조회가 무조건 빨라질까요? 아닙니다. 인덱스는 만병통치약이 아닙니다. 쓰기 성능과 메모리를 담보로 잡고 읽기 속도를 빌려오는 대출에 가깝습니다.
카디널리티를 모르면 인덱스는 짐이 됩니다
지난달 2년 차 멘티 한 분이 찾아왔습니다. 주문 목록 조회가 4초 이상 지연되자 주문 상태(status)와 결제 여부(is_paid) 컬럼에 인덱스를 각각 걸었다고 했습니다. 결과는 어땠을까요? 응답 속도는 0.1초도 빨라지지 않았습니다.
데이터 120만 건 중에서 주문 상태는 기껏해야 네 가지였습니다. 값의 고유성이 낮은 컬럼에서는 B-Tree 인덱스를 탐색하는 비용이 테이블 전체를 한 번에 훑는 비용보다 더 큽니다. 옵티마이저는 결국 인덱스를 무시하고 풀 테이블 스캔을 선택했습니다.
공짜로 빨라지는 기술은 세상에 없습니다
인덱스를 하나 추가할 때마다 데이터베이스는 보이지 않는 대가를 치릅니다.
INSERT가 일어날 때마다 새로운 인덱스 트리에 노드를 추가하고 균형을 맞춥니다. UPDATE나 DELETE가 발생할 때도 마찬가지입니다. 인덱스 페이지가 쪼개지는 페이지 분할(Page Split)이 발생하면 디스크 I/O가 요동칩니다.
읽기 쿼리 몇 밀리초를 아끼겠다고 만든 인덱스가, 정작 트래픽이 몰릴 때 주문 저장 API를 멈춰 세우는 원인이 됩니다. 배보다 배꼽이 더 커지는 셈입니다.
인덱스를 걸기 전에 실행 계획부터 뜯어보십시오
조회가 느릴 때 개발자가 가장 먼저 켜야 하는 것은 인덱스 생성 창이 아닙니다. 데이터베이스가 쿼리를 어떻게 해석하는지 보여주는 실행 계획(EXPLAIN)입니다.
실제로 데이터 몇 건을 읽고 버리는지, 임시 테이블을 생성하고 정렬하느라 병목이 생겼는지부터 확인해야 합니다. 쿼리의 불필요한 서브쿼리를 조인으로 풀거나 페이징 구조만 바꿔도 인덱스 없이 3초짜리 쿼리가 0.05초로 떨어지는 경우가 수두룩합니다.
원인을 모르고 약을 먹으면 병이 낫지 않습니다. 인덱스는 병목의 위치를 정확히 확인한 뒤에 꺼내는 마지막 카드여야 합니다.
인덱스를 늘리는 개발자가 아니라, 불필요한 인덱스를 과감히 지울 수 있는 개발자가 실력자입니다. 지금 여러분의 데이터베이스에 걸려 있는 인덱스 목록을 열어보십시오. 그중에 단 한 번도 타지 않으면서 쓰기 성능만 갉아먹고 있는 인덱스가 분명히 있습니다.