[Django] - N + 1 Problem


Django의 ORM은 Lazy-Loading 방식이다. 바로 데이터를 가져오는 것이 아니라 모든 처리가 끝나고 호출 시점에서 쿼리를 실행한다.

# 아직 쿼리를 보내지 않았다.
items = item.objects.all()

for item in items:
	# 호출 시점에서 쿼리를 날린다.
	# 문제는 서브 item 즉 Join이 필요한 데이터는 1번 호출이면 끝날 쿼리를
	# N번 만큼 호출 하게 된다.
	print(item.sub_item)

이걸 해결하는 방법은 Lazy-Loading이 아니라 Eager-Loading 즉, 바로 쿼리를 보내는 방식으로 해결이 가능하다.

# select_related로 데이터를 바로 가져왔다. (Join)
items = item.objects.select_related('sub_item).all()

for item in items:
	# 이미 데이터가 있기 때문에 그냥 순회를 돈다.
	# 1번의 쿼리로 처리가 되었다.
	print(item.sub_item)

  • select_related : foreign-key로 연결된 single-valued relationship에서만 사용 가능하다. JOIN을 통해 데이터를 가져온다.
  • prefetch_related : many-to-many, many-to-one 등 모든 relationship에서 사용 가능하다. SQL의 WHERE … IN 구문을 사용한 방법이다.