DB Index, 언제 어떻게 추가해야 쿼리 속도가 빨라질까?
데이터가 많아지면서 느려지는 Django ORM 쿼리를 인덱스로 최적화하는 방법을 학습. 인덱스의 원리부터 실무 적용까지 체계적으로 다룸
인덱스 기본 원리
인덱스가 없다면
데이터베이스는 모든 행을 처음부터 끝까지 스캔하는 Full Table Scan 실행
데이터가 수십만, 수백만 건으로 늘어나면 엄청난 I/O 비용 발생
인덱스란
특정 컬럼의 값과 해당 행의 물리적 주소를 키-값 쌍으로 저장하는 목차
B-Tree 자료구조 사용으로 O(log N) 시간 복잡도 보장
=,BETWEEN,LIKE 'prefix%'같은 범위 검색에도 효율적
Django에서 인덱스 추가 방법
단일 컬럼 인덱스
class Post(models.Model):
status = models.CharField(max_length=10, db_index=True)다중 컬럼 인덱스 및 고급 옵션
class Product(models.Model):
category = models.ForeignKey('Category', on_delete=models.PROTECT)
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
class Meta:
indexes = [
models.Index(fields=['category', '-price']), # 다중 컬럼
models.Index(fields=['name']), # 단일 컬럼
]인덱스 추가 시점
WHERE 절
filter(), exclude(), get() 조건 컬럼
Post.objects.filter(status='published')
JOIN
ForeignKey, OneToOneField 키 컬럼
Post.objects.filter(author__name='User')
ORDER BY 절
order_by() 정렬 기준 컬럼
Post.objects.order_by('-created_at')
GROUP BY 절
annotate()와 values() 그룹화 기준
Sale.objects.values('category').annotate(total=Sum('amount'))
참고: Django는 ForeignKey에 자동으로 인덱스 생성
인덱싱 전략
다중 컬럼 인덱스 순서
Index(fields=['A', 'B'])는WHERE A = ?와WHERE A = ? AND B = ?에만 효과WHERE B = ?에는 효과 없음가장 선택도가 높고 자주 사용되는 컬럼을 맨 앞에 배치
커버링 인덱스
쿼리에 필요한 모든 정보를 인덱스가 포함
실제 테이블 접근 없이 인덱스 스캔만으로 결과 반환
테이블 접근 I/O가 완전히 사라져 매우 빠른 성능
주의사항
성능 트레이드오프
조회(SELECT) 성능 향상 vs 생성/수정/삭제(INSERT/UPDATE/DELETE) 성능 저하
인덱스가 많을수록 CUD 작업 속도 감소
추가 저장 공간 필요
비효율적인 경우
LIKE '%word'(앞부분 와일드카드)WHERE status != 'active'(부정형 조건)카디널리티가 낮은 컬럼 (성별, boolean 값 등)
사용되지 않는 인덱스는 리소스 낭비
성능 개선 프로세스
느린 API 엔드포인트 발견
django-debug-toolbar로 느린 SQL 쿼리 특정
EXPLAIN ANALYZE로 실행 계획 분석
Seq Scan(Full Scan) 확인시 적절한 인덱스 설계
마이그레이션 실행 후 Index Scan으로 변경 확인
EXPLAIN ANALYZE 활용
쿼리 실행 계획과 실제 실행 시간 확인
Seq Scan → Index Scan 변경으로 성능 개선 검증
실행 시간 단축 효과 측정
Last updated
