Django ORM 쿼리 최적화

Django ORM은 데이터베이스 작업을 쉽게 만들어 줍니다. 하지만 그 이면에는 위험이 숨어 있습니다. 연관된 객체를 잘못 가져오면 N+1 쿼리 문제가 발생합니다.

이는 100개의 포스트를 가져올 때, 앱이 101번의 쿼리를 실행할 수도 있음을 의미합니다. 이는 앱의 성능을 급격히 저하시킵니다.

이를 해결하기 위해 다음 두 가지 도구를 사용하세요:

  1. select_related

ForeignKeyOneToOneField에 사용하세요.

SQL JOIN을 사용합니다. 단 한 번의 쿼리로 연관 데이터를 가져옵니다.

  • 예시: Post는 하나의 Author를 가집니다.
  • 비효율적인 방식: 100개의 포스트에 대해 101번의 쿼리 실행.
  • 최적화된 방식: .select_related("author")를 사용하여 1번의 쿼리로 실행.
  1. prefetch_related

ManyToManyField와 역방향 ForeignKey에 사용하세요.

별도의 쿼리를 실행한 뒤 Python에서 이를 결합합니다.

  • 예시: Post는 여러 개의 Tags를 가집니다.
  • 비효율적인 방식: 포스트를 위한 1번의 쿼리 + 각 포스트의 태그를 위한 쿼리가 매번 실행됨.
  • 최적화된 방식: .prefetch_related("tags")를 사용하여 총 2번의 쿼리로 실행.

전문가 팁:

  • 루프에 진입하기 전에 Prefetch 객체를 사용하여 연관 데이터를 필터링하세요.
  • 이들을 체이닝(chaining)할 수 있습니다. 하나의 queryset에서 두 가지를 모두 사용하여 작성자와 태그를 한 번에 가져올 수 있습니다.
  • 루프 내부에서 이미 prefetch된 관계에 .filter()를 호출하지 마세요. 이는 캐시를 우회하여 데이터베이스에 다시 접근하게 만듭니다.
  • select_related와 함께 .only()를 사용하여 필요한 컬럼만 가져오세요.

요약:

  • ForeignKey / OneToOne: select_related 사용.
  • ManyToMany / 역방향 FK: prefetch_related 사용.

django-debug-toolbar를 사용하여 쿼리 횟수를 확인하고 이러한 문제를 조기에 발견하세요.

출처: https://dev.to/fhva29/optimizing-django-orm-queries-a-practical-guide-to-selectrelated-and-prefetchrelated-1gpl