우아한테크코스 테코톡

피글렛의 소소한 쿼리 튜닝 팁

https://youtu.be/WFjxWcr90gg?si=4l7bsoEuHye9g0k5

피글렛의 소소한 쿼리 튜닝 팁


쿼리 튜닝, 언제 어떻게 해야 할까? (P99 기반 판단 + 인덱스 전략 정리)

쿼리 튜닝은 단순히 SQL을 “조금 더 빠르게” 만드는 작업이 아니다. 실제로는 DB가 데이터를 어떻게 읽고 처리하는지 전체 흐름을 최적화하는 과정이다. 발표에서도 강조하듯, 실행 계획을 분석하고 불필요한 작업을 제거해 응답 시간을 최소화하는 것이 핵심이다.

많은 개발자가 “쿼리 튜닝 = SQL 수정”이라고 생각하지만, 실제로는 다음 영역까지 포함한다.

  • SQL 구조 개선
  • 인덱스 설계
  • 데이터 모델링 개선
  • 캐싱 전략 적용

이 중에서도 가장 효과가 크고 즉각적인 방법이 바로 인덱스 활용이다.


언제 쿼리 튜닝을 해야 할까? (핵심: P99)

튜닝은 감으로 하면 안 된다. 반드시 지표 기반으로 판단해야 한다. 그 기준으로 가장 많이 사용하는 것이 바로 P99 지표다.

일반적으로 시스템 응답 시간은 다음처럼 나뉜다.

  • P50: 일반적인 사용자 경험
  • P90: 대부분 사용자 경험
  • P99: 최악의 사용자 경험

발표에서 중요한 포인트는 이 부분이다.

P50, P90은 완만한데 P99만 급격히 증가한다면 → 쿼리 튜닝 신호다

이 의미는 명확하다.

  • 평균은 괜찮다
  • 하지만 일부 요청이 심각하게 느리다
  • 그 원인은 대부분 특정 쿼리 병목

즉, 튜닝은 “전체가 느릴 때”가 아니라 “일부 요청이 비정상적으로 느려질 때” 시작해야 한다


쿼리 튜닝의 핵심: 실행 계획(EXPLAIN)

튜닝의 시작은 항상 이것이다.

EXPLAIN SELECT ...

여기서 특히 중요하게 봐야 할 컬럼은 두 가지다.

1. type (접근 방식)

  • ALL → 풀 테이블 스캔 (최악)
  • ref / range → 인덱스 사용 (좋음)

2. Extra (추가 작업)

  • Using filesort → 정렬을 DB 엔진이 직접 수행 (비효율)
  • Using index → 인덱스만으로 처리 (최적)

이 두 개만 봐도 쿼리 상태를 거의 판단할 수 있다.


시나리오 1: 최신 데이터 조회 (정렬 + 필터)

문제 상황

SELECT *
FROM articles
WHERE member_id = ?
ORDER BY created_at DESC;

데이터 300만 건 기준:

  • 실행 시간: 약 4초

실행 계획 문제

  • type = ALL → 풀 테이블 스캔
  • Extra = Using filesort → 정렬을 DB가 직접 수행

👉 문제 요약

  • WHERE도 느림
  • ORDER BY도 느림

해결: 컴포지트 인덱스

INDEX(member_id, created_at DESC)

이 인덱스 하나로 두 문제를 동시에 해결한다.

  • member_id → 필터링 최적화
  • created_at → 정렬 최적화

👉 결과

  • type: ALL → ref
  • filesort 제거
  • 실행 시간: 4초 → 0.01초

📌 핵심 인사이트

WHERE + ORDER BY 조합이면 → 컴포지트 인덱스


시나리오 2: 일부 컬럼만 조회

문제 상황

SELECT id, title
FROM articles
WHERE member_id = ?;

실행 시간: 약 3.5초

문제 원인

  • 필요한 컬럼: 2개
  • 실제 읽는 데이터: 모든 컬럼

👉 불필요한 디스크 I/O 발생


해결: 커버링 인덱스

INDEX(member_id, title)

(InnoDB는 PK를 자동 포함 → id 포함 효과)

👉 결과

  • Extra: Using index
  • 테이블 접근 없이 인덱스만 조회
  • 실행 시간: 3.5초 → 0.5ms

📌 핵심 인사이트

필요한 컬럼이 적다면 → 커버링 인덱스


컴포지트 vs 커버링 인덱스 (헷갈리는 핵심 정리)

이 둘은 서로 다른 개념이다.

컴포지트 인덱스

  • 기준: 컬럼 개수
  • 목적: WHERE + ORDER BY 최적화
  • 예: (member_id, created_at)

커버링 인덱스

  • 기준: 쿼리 커버 여부
  • 목적: 테이블 접근 제거 (I/O 제거)
  • 예: (member_id, title)

👉 중요한 포인트

  • 서로 배타적이지 않다
  • 하나의 인덱스가 둘 다 될 수 있다

발표에서도 두 번째 케이스는 컴포지트 + 커버링 인덱스라고 설명한다.


실무에서 바로 쓰는 판단 기준

이걸 기억하면 거의 80% 해결된다.

1. WHERE + ORDER BY 있다

→ 컴포지트 인덱스

2. SELECT 컬럼 적다

→ 커버링 인덱스

3. type = ALL 나온다

→ 인덱스 필요

4. Using filesort 보인다

→ 정렬 인덱스 필요

5. P99 튄다

→ 쿼리 튜닝 타이밍


한 단계 더 깊은 관점 (중요한 통찰)

이 발표에서 가장 중요한 메시지는 기술이 아니다.

👉 “언제 튜닝해야 하는가”

많은 시스템이 이런 실수를 한다.

  • 미리 인덱스를 과도하게 만든다
  • 또는 느려질 때까지 방치한다

하지만 가장 좋은 전략은 이것이다.

P99 기반 → 병목 확인 → 실행 계획 분석 → 인덱스 적용

즉, 데이터 기반 + 최소 개입


마무리

쿼리 튜닝은 “빠르게 만드는 기술”이 아니라 불필요한 일을 하지 않게 만드는 기술이다.

핵심은 단 3가지다.

  • 언제: P99가 튄다
  • 어디: EXPLAIN으로 확인한다
  • 어떻게: 인덱스로 해결한다

그리고 그 인덱스 전략은 두 가지로 압축된다.

  • 컴포지트 인덱스 → 정렬 + 필터 최적화
  • 커버링 인덱스 → I/O 제거

이 두 개만 제대로 이해해도 대부분의 실무 성능 문제는 해결된다.



© 2020. All rights reserved.

SIKSIK