본문 바로가기

Django ORM으로 효율적인 데이터 쿼리 작성하기

_Big 2025. 5. 14.
반응형

django 로고 이미지


Django의 ORM(Object-Relational Mapping)은 프레임워크에서 가장 강력한 기능 중 하나입니다. SQL 쿼리를 파이썬 코드로 추상화하여 직관적인 객체 지향 문법으로 데이터베이스와 상호작용할 수 있게 해줍니다. 하지만 효율적인 쿼리를 작성하는 것은 또 다른 이야기입니다—성능 좋은 앱과 느린 앱을 가르는 핵심 차이점이 되기도 하죠.

서론

Django의 ORM은 SQL을 직접 작성하지 않아도 데이터베이스를 쉽게 쿼리할 수 있도록 해줍니다. 초반에는 매우 편리하지만, 애플리케이션이 커지면 쿼리 최적화가 필수입니다. 비효율적인 ORM 사용은 불필요한 데이터베이스 접근, 높은 메모리 사용량, 느린 페이지 로딩으로 이어질 수 있습니다.

이 가이드에서는 Django ORM을 사용해 깔끔하고 성능 좋은 쿼리를 작성하는 방법을 다룹니다. 기본 필터링부터 복잡한 조인과 성능 팁까지, ORM 쿼리 실력을 한 단계 끌어올려 봅시다.

1. QuerySet의 실행 시점을 이해하라

Django의 QuerySet은 지연 평가(lazy evaluation) 방식입니다. 즉, 쿼리셋 메서드를 호출해도 실제로 쿼리가 실행되지는 않으며, 데이터가 필요할 때 비로소 실행됩니다.

books = Book.objects.filter(is_available=True)  # 아직 쿼리 실행 X
for book in books:  # 이 시점에서 쿼리 실행
    print(book.title)

이 특성을 활용하면 필터를 체이닝하고 필요할 때까지 쿼리 실행을 미룰 수 있습니다. 루프 내에서 반복적으로 쿼리를 실행하지 않도록 주의하세요.

 

2. select_related와 prefetch_related를 현명하게 사용하라

관계 모델을 다룰 때 쿼리 수를 줄이는 데 유용한 두 가지 메서드:

  • select_related: 외래 키(OneToOne, ForeignKey)에 사용 (SQL JOIN 수행)
  • prefetch_related: ManyToMany 또는 역방향 ForeignKey에 사용 (여러 쿼리 후 파이썬에서 결합)

예시:

# 최적화 전
books = Book.objects.all()
for book in books:
    print(book.author.name)  # 반복마다 쿼리 실행

# 최적화 후
books = Book.objects.select_related('author')

관계의 종류에 따라 적절한 메서드를 사용하는 것이 성능 최적화의 핵심입니다.

 

3. 정밀한 필터링과 집계 사용

ORM을 활용하면 필터링과 집계를 간결하고 읽기 쉽게 작성할 수 있습니다.

# 필터링
available_books = Book.objects.filter(is_available=True)

# 개수 카운트
total_books = Book.objects.count()

# 평균 구하기
from django.db.models import Avg
avg_pages = Book.objects.aggregate(Avg('page_count'))

annotate()를 사용하면 결과 객체마다 계산된 필드를 추가할 수 있습니다. 예: 저자의 책 개수 표시.

from django.db.models import Count
authors = Author.objects.annotate(book_count=Count('book'))

전체 모델 데이터를 다 쓸 필요가 없다면 .only() 또는 .defer()로 필요한 필드만 불러오세요.

 

4. N+1 쿼리 문제 피하기

N+1 문제란, 루프를 돌며 관계 데이터를 접근할 때 매번 추가 쿼리가 발생하는 현상을 말합니다. 이런 상황을 미리 예측하고 필요한 데이터를 미리 불러오는 것이 중요합니다.

# 잘못된 예: 책 1개 + 저자 N개 = N+1 쿼리
for book in Book.objects.all():
    print(book.author.name)

# 올바른 예
for book in Book.objects.select_related('author'):
    print(book.author.name)

Django Debug Toolbar 같은 프로파일링 도구를 활용하면 이런 문제를 빠르게 발견하고 수정할 수 있습니다.

 

5. ORM 성능을 위한 베스트 프랙티스

다음은 ORM 쿼리를 빠르고 효율적으로 유지하기 위한 핵심 팁입니다:

  • 자주 조회되는 필드에는 인덱스를 추가
  • .all()은 정말 필요할 때만 사용
  • 대용량 결과는 반드시 Paginator로 페이지 처리
  • 존재 여부 확인 시 .count() 대신 .exists() 사용
  • 자주 쓰이는 쿼리는 캐싱(뷰 캐시 또는 로우 레벨 캐시)으로 처리

애플리케이션이 커질수록 실제 데이터로 쿼리를 테스트하고, 주기적으로 성능을 점검하세요.

 

마치며

Django ORM은 읽기 쉽고 유지보수하기 쉬운 데이터 로직을 작성하게 해줍니다. 하지만 한 발 더 나아가 깊이 있는 도구와 패턴을 익히면, 여러분의 앱은 더 우아하고 빠르며 확장 가능해집니다.

가장 까다로웠던 ORM 쿼리 작성 경험이 있으신가요? 댓글로 공유해 주세요—여러분의 쿼리를 함께 개선해보고 싶습니다!

 

 

Django 모델링: 데이터베이스 설계의 핵심

강력한 웹 애플리케이션은 모두 잘 구조화된 데이터베이스 위에 구축됩니다. Django 세계에서는 데이터를 제대로 모델링하는 것이 모든 것의 출발점입니다—사용자 인터랙션부터 백엔드 처리까

bigadmin.org

 

반응형

댓글