2019.08.27 django queryset filter와 exists()의 차이

django의 쿼리는 마지막까지 지연(lazy)된다.

  • 예를 들어 filter를 건다고 하면, 이것은 DB에 바로 전달되지 않는다.
    person = Person.objects.filter(first_name='kim')
  • 해당 쿼리셋은 바로 실행되지 않는다.
  • DB에 쿼리를 전달하는 일은 웹 애플리케이션이 느려지는 주범 중 하나이기 때문이다.
  • 실제로 실행 되려면 다음과 같은 과정이 실행될 때 일어난다.

for one_person in person:
print(one_person)

  • 해당 과정이 일어나게 되면 실제로 DB에 전달되면서 발생하게 된다.

DB 쿼리셋은 대신 캐시된다.

  • DB쿼리는 단 한번만 발생한다. 똑같은 순회를 할 경우 DB쿼리는 한번만 시행된다.

for one_person in person:
print(one_person.firstname)

for one_person in person:
print(one_person.lastname)

  • 해당 쿼리셋은 한번만 DB에 접근하여 캐시로 해당 값을 가지고 있고 아래의 for문을 해결한다.

if문에서는 쿼리셋 평가가 발생한다.

restaurant_set = Restaurant.objects.filter(cuisine="Indian")

if 문은 쿼리셋을 '평가'한다

if restaurant_set:
# 순회할 때는 캐시된 쿼리셋이 사용된다
for restaurant in restaurant_set:
print(restaurant.name)

  • 오홋 신기하네.
  • 하지만 해당 경우 만약에 있는지 없는지만을 평가할 떄는 캐시가 문제가 된다.
  • 따라서 했는지 없는지만을 평가하기 위해서는 exists()라는 것을 활용한다.

존재만을 확인하기 위한 exists()

if restaurant_set.exists():
실행한 내용

  • 이렇게 되면 exists를 통해 존재만을 확인한다.

하지만 쿼리셋 캐시도 엄청 크다고 하면, 문제가 발생된다.

  • 해당 경우 exists()와 iterator()를 함께 사용하여 쿼리셋 캐시를 생성하는 일을 방지할 수 있다.

person = Person.objects.all()

if person.exists():
for one_person in person.iterator():
print(one_person)

  • 해당 과정을 통해서 첫 번째 exists()로 쿼리셋 레코드가 존재하는지 확인하고
  • 존재가 한다고 하면 iterator()를 통해서 하나씩 돌면서 캐시를 쌓지 않고, 프린트를 하게 된다.

'Django' 카테고리의 다른 글

Django migration 되돌리기, 재실행 방법  (3) 2020.01.29
Django select_related, prefetch_related에 대해서  (0) 2019.12.28
Django Lock에 관해서  (0) 2019.12.28
Django model(default, blank, null)  (0) 2019.12.28
Django admin message  (1) 2019.12.28

+ Recent posts