DatabaseIndexPerformance

인덱스를 추가하기 전에 먼저 확인했던 조회 패턴

쿼리가 느리다고 바로 인덱스를 추가하기보다, 어떤 조회 패턴에서 병목이 생기는지부터 확인해야 했던 이유를 실무 기준으로 정리했습니다.

Srue2026년 4월 2일
인덱스를 추가하기 전에 먼저 확인했던 조회 패턴

쿼리가 느려지기 시작하면 가장 먼저 떠오르는 해결책은 보통 인덱스입니다.
저도 한동안은 그랬습니다. 실행 시간이 길면 "이 컬럼에 인덱스 하나 걸면 되겠지"라고 생각했습니다.

그런데 실무에서는 그렇게 단순하게 풀리지 않는 경우가 많았습니다.
인덱스를 추가했는데도 기대만큼 빨라지지 않거나, 반대로 쓰기 성능만 나빠지는 경우도 있었습니다.

결국 느린 쿼리를 볼 때는 인덱스 자체보다, 어떤 조회 패턴으로 데이터가 읽히는지를 먼저 보는 쪽으로 습관이 바뀌었습니다.

처음엔 where 절 컬럼만 보고 인덱스를 생각했다

예전에는 이런 식으로 봤습니다.

select *
from orders
where user_id = ?
order by created_at desc
limit 20;

그러면 바로 user_id에 인덱스를 추가하려고 했습니다.
물론 틀린 접근은 아니지만, 실제로는 그것만으로 부족한 경우가 많았습니다.

이 쿼리는 단순히 where user_id = ?만 보는 게 아니라,

  • 어떤 조건이 함께 들어오는지
  • 정렬은 무엇인지
  • limit이 붙는지
  • 조인 뒤에 필터링하는지

를 같이 봐야 했습니다.

가장 먼저 보는 건 요청 패턴이다

실무에서는 동일한 테이블이라도 조회 방식이 화면마다 달랐습니다.

  • 사용자별 최근 주문 조회
  • 상태별 주문 검색
  • 기간별 정산 조회
  • 관리자 상세 검색

이걸 하나의 인덱스로 다 해결하려 하면 금방 복잡해집니다.
그래서 지금은 쿼리 하나만 보지 않고, 어떤 화면에서 어떤 조건 조합이 반복되는지를 먼저 묶어 봅니다.

이 단계 없이 인덱스를 넣으면 "느린 쿼리 하나"는 잠깐 빨라져도, 전체 패턴과는 맞지 않을 때가 많았습니다.

정렬 조건을 같이 보지 않으면 체감이 작았다

조회가 느린데 필터 컬럼만 보고 인덱스를 넣으면, 정렬 단계에서 다시 비용이 커지는 경우가 있었습니다.

예를 들어 사용자별 최근 주문 목록이라면,

  • where user_id = ?
  • order by created_at desc

를 같이 보게 됩니다.

이 경우 실무에서는 단일 인덱스보다 복합 인덱스를 먼저 검토하는 편이 낫습니다.
필터와 정렬이 같이 자주 쓰이는 패턴이라면, 조회 체감 차이가 꽤 컸습니다.

select 절과 조인 구조도 같이 본다

인덱스를 추가해도 여전히 느릴 때는, 결국 읽어오는 데이터 양이 너무 많았던 경우가 많았습니다.

  • select *로 불필요한 컬럼까지 읽고 있는지
  • 조인이 너무 이른 단계에서 일어나는지
  • 조건 필터보다 조인이 먼저 커지는지

실무에서는 인덱스를 넣기 전에 쿼리 자체를 더 가볍게 만들 수 있는 경우가 꽤 있었습니다.
오히려 이쪽이 더 큰 효과를 내는 경우도 많았습니다.

실행 계획은 꼭 본다

느린 쿼리를 볼 때 제일 후회했던 순간은, 실행 계획도 안 보고 인덱스부터 넣었던 때였습니다.

실행 계획을 보면 최소한 아래는 확인할 수 있습니다.

  • 풀 스캔이 나는지
  • 인덱스를 타긴 타는지
  • 어떤 인덱스를 선택했는지
  • 정렬이나 임시 테이블 비용이 큰지

실무에서는 "인덱스가 있다"와 "그 인덱스를 잘 탄다"가 전혀 다른 이야기였습니다.

중복 인덱스도 생각보다 자주 생긴다

급하게 대응하다 보면 비슷한 인덱스가 여러 개 생기기도 합니다.

  • idx_orders_user_id
  • idx_orders_user_id_created_at

이런 식으로 추가하다 보면, 실제로는 하나로 충분한데 관리 대상만 늘어나는 경우가 있었습니다.
쓰기 비용과 저장 비용도 무시할 수 없어서, 인덱스는 늘릴수록 좋다는 생각은 위험했습니다.

지금은 이렇게 확인한다

인덱스를 추가하기 전에는 보통 아래 순서로 봅니다.

  1. 느린 쿼리가 어느 화면에서 반복되는가
  2. where, order by, limit 조합이 어떻게 되는가
  3. 실행 계획에서 어디가 병목인가
  4. 인덱스보다 쿼리 구조를 먼저 줄일 수 있는가
  5. 새 인덱스가 기존 인덱스와 겹치지 않는가

이 순서를 거치고 나면 "무조건 인덱스 추가"보다 훨씬 덜 흔들리게 됩니다.

마무리

실무에서 인덱스는 느린 쿼리를 고치는 도구이기도 했지만, 그보다 조회 패턴을 이해했는지 확인하는 지표에 가까웠습니다.

결국 쿼리를 빠르게 만드는 건 인덱스 하나를 추가하는 행위보다,
어떤 화면이 어떤 방식으로 데이터를 읽는지 먼저 이해하는 데서 시작된다고 느꼈습니다.