우아한테크코스 테코톡
피글렛의 소소한 쿼리 튜닝 팁
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 제거
이 두 개만 제대로 이해해도 대부분의 실무 성능 문제는 해결된다.