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()를 통해서 하나씩 돌면서 캐시를 쌓지 않고, 프린트를 하게 된다.