Django ORM 쿼리 최적화 메서드

송용진·2025년 8월 4일

Python / Django

목록 보기
15/23

SQL JOIN 으로 한 번의 쿼리로 관련 객체까지 가져옴

# models.py
class User(models.Model):
    username = models.CharField(max_length=100)

class UserBlock(models.Model):
    blocker = models.ForeignKey(User, related_name='blocking', on_delete=models.CASCADE)
    blocked_user = models.ForeignKey(User, related_name='blocked', on_delete=models.CASCADE)

일반 쿼리

blocked = UserBlock.objects.filter(blocker=user)
for b in blocked:
    print(b.blocked_user.nickname)  # ← 여기가 매번 추가 쿼리를 발생시킴 (N+1 문제)

→ 위 코드에서 blocked_user.nickname을 조회할 때마다
별도의 쿼리가 실행됨
→ 유저 10명을 차단한 경우,
총 1 (UserBlock 쿼리) + 10 (blocked_user 조회) = 11개의 쿼리

blocked = UserBlock.objects.filter(blocker=user).select_related('blocked_user')
for b in blocked:
    print(b.blocked_user.nickname)  # ← 이미 join된 상태, 추가 쿼리 없음

→ 이 경우는 SQL 내부에서 JOIN으로 묶어서 단 한 번의 쿼리로 모두 가져옴

두 번의 쿼리로 관련 객체를 가져오고, 파이썬이 메모리에서 매핑

# models.py
class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)

일반 쿼리

books = Book.objects.all()  # 쿼리 1번

for book in books:
    for author in book.authors.all():  # ❗ 각 book마다 추가 쿼리
        print(f"{book.title} by {author.name}")
books = Book.objects.prefetch_related("authors")  # 쿼리 2번 (Book + Author)

for book in books:
    for author in book.authors.all():  # ✅ 이미 메모리에 로드됨, 추가 쿼리 없음
        print(f"{book.title} by {author.name}")

SELECT FROM book
SELECT
FROM author WHERE id IN (...)

쿼리는 2번
반복 접근해도 추가 쿼리 없음
대규모 데이터일수록 성능 차이 큼

차이점

profile
개발자

0개의 댓글