---
type: knowledge
domain: data
status: active
last-reviewed: 2026-07-07
---

# SQL 성능과 인덱스 실전

> 한 줄 정의
> 느린 쿼리의 답은 추측이 아니라 **실행 계획**이다. 모델링·저장소 선택은 [[데이터 원리]], 분석 쿼리의 논리 함정은 [[데이터 분석 원리]] — 여기는 읽기·쓰기 성능의 실전이다.

## 인덱스가 있는데 안 타는 경우 — 단골 목록

| 패턴 | 왜 못 타나 | 처방 |
|------|-----------|------|
| `WHERE UPPER(email) = ...` | 컬럼을 함수로 감싸면 인덱스 무효 | 함수 기반 인덱스 또는 저장 시 정규화 |
| `LIKE '%keyword'` | 앞 와일드카드는 시작점을 못 찾음 | 전문 검색 인덱스로 전환 |
| `WHERE phone = 01012345678` (문자 컬럼에 숫자) | 암묵적 형변환이 컬럼을 감싼 것과 동일 | 타입을 맞춰 비교 |
| `OR` 양쪽 다른 컬럼 | 한쪽만 인덱스면 전체 스캔 | 양쪽 인덱스 또는 UNION 분리 |
| 복합 인덱스의 뒤 컬럼만 조건 | 인덱스는 왼쪽부터 순서대로만 | 인덱스 컬럼 순서 재설계 |

복합 인덱스 순서 원칙([[데이터 원리]] 재확인): **등호 조건 컬럼 → 범위 조건 컬럼** 순.

## 실행 계획 읽기 — 3가지만 본다

1. **스캔 방식**: 전체 스캔(Seq Scan)이 항상 악은 아니다 — 작은 테이블·대부분의 행을 읽는 쿼리엔 정상. "큰 테이블 + 좁은 조건 + 전체 스캔" 조합만 사고다.
2. **추정 행수 vs 실제 행수**: 두 값이 자릿수로 차이 나면 통계가 낡은 것 — 통계 갱신(ANALYZE)이 인덱스 추가보다 먼저다. 옵티마이저는 통계로 판단하기 때문에 통계가 틀리면 계획이 틀린다.
3. **어느 노드에서 시간을 쓰나**: 전체의 90%를 먹는 노드 하나를 찾는다 — 최적화는 거기서만.

## N+1 — ORM의 대표 사고

목록 100건 조회 후 루프에서 연관 데이터를 건별 조회 = 쿼리 101번. 코드에는 반복문 하나뿐이라 눈에 안 보인다.

- 탐지: 쿼리 로그에서 **같은 모양 쿼리의 연발**을 찾는다 (개발 환경에서 쿼리 카운트 알림이 최선).
- 처방: eager loading / JOIN / IN 배치 조회.
- 예방: "목록 화면 = N+1 의심"을 리뷰 체크 항목으로.

## 페이지네이션 — OFFSET은 깊어질수록 느려진다

- `OFFSET 100000`은 10만 행을 **읽고 버리는** 연산이다 — 뒤 페이지로 갈수록 선형 악화.
- 처방: keyset(커서) 페이지네이션 — `WHERE id < 마지막본ID ORDER BY id DESC LIMIT n`. 무한 스크롤·API 목록의 기본값.
- OFFSET이 허용되는 곳: 얕은 페이지만 쓰는 관리자 화면 정도.

## COUNT · 집계의 비용

- 대형 테이블의 정확한 `COUNT(*)`는 비싸다 — 목록 UI의 "전체 12,847건"이 진짜 필요한지부터 의심 ("더 보기"로 충분한 경우가 많다).
- 대시보드 집계는 실시간 원본 집계 대신 주기 집계 테이블/머티리얼라이즈드 뷰 — 단, 갱신 주기를 화면에 표기.

## 락과 긴 트랜잭션

- 느린 시스템의 범인이 쿼리가 아니라 **락 대기**인 경우가 많다 — "빠른 쿼리인데 가끔 몇 초"는 락 의심.
- 긴 트랜잭션이 최대 적: 트랜잭션 안에서 외부 API 호출·무거운 계산 금지 ([[데이터 원리]] 재확인).
- 운영 중 스키마 변경(ALTER)은 테이블 락을 잡을 수 있다 — DB·버전별 온라인 DDL 지원을 확인하고, 대형 테이블은 배포 창구에서. → [[배포 전략 실전]] expand-contract.

## 인덱스는 공짜가 아니다

- 인덱스 하나 = 쓰기마다 갱신 비용 + 저장 공간. "혹시 몰라서" 인덱스는 쓰기 성능 세금이다.
- 사용되지 않는 인덱스를 주기적으로 확인해 제거한다 (DB 통계 뷰로 조회 가능).

## 관련 문서

- [[데이터 원리]] — 모델링·트랜잭션·저장소 선택
- [[데이터 분석 원리]] — 분석 쿼리의 논리 함정 (JOIN fan-out 등)
- [[백엔드 원리]] — 페이지네이션 상한·캐시 채택 기준
- [[배포 전략 실전]] — 마이그레이션과 배포 순서
