사이트에서 Get 방식으로 가져오는 API 하나가 1.5초 정도로 너무 오래 걸린다 싶었는데 django-debug-toolbar(공식문서)의 SQL탭을 보니 쿼리를 150번 정도 돌리고 있었다.
그렇게 복잡한 API도 아니었는데 이렇게 쿼리를 많이 돌리는 이유를 보니,
- serializer에서 다른 테이블을 참조
- for loop로 QuerySet을 돌림
이 중 두 번째, for loop로 QuerySet을 돌리는 실수가 가장 치명적이었다.
심지어 for loop 아래의 for loop에서까지 돌리고 있었다.
쿼리 1-10개 정도야 반짝하고 가져오지만 100개가 넘어가면...
그래서 for loop 아래에서 Model.objects.filter(..) 등으로 QuerySet을 가져오는 부분을 모두 바깥으로 뺐다.
그런데 수정 후 API를 돌려보니 쿼리 수가 내 생각만큼 줄지 않았다.
이유인즉슨 QuerySet은 게으르기 때문이라고.
people_qs = People.objects.filter(active=True)
위와 같이 QuerySet을 변수에 할당하기만 하면 쿼리가 실행될 것 같은 느낌적인 느낌이 들지만 QuerySet이 무언가를 하기 전까지는 쿼리가 실행되지 않는다!
따라서 저렇게 QuerySet을 people_qs 변수에 할당하고나서 for loop 안에서 people_qs를 부르면 그 loop만큼 쿼리가 실행된다.
QuerySet이 evaluate되는 조건은 Django 문서에 나와있다.
나는 이중 list()로 다른 변수에 QuerySet의 결과를 저장한 뒤 사용했다.
코드가 이전보다 좀 추가되긴 했지만 150개 가까이 됐던 쿼리를 중복 없이 7개로 줄였다!
API 호출 시간도 1.4s에서 0.2-0.3s 정도로 줄어들었다.
'개발 > Django' 카테고리의 다른 글
[Django] Designing Better Models (0) | 2019.05.12 |
---|---|
[Django] Class-Based Views vs. Function-Based Views (4) | 2019.02.19 |
[Django] Django 에러 핸들링 (3) | 2019.02.12 |
[Django] ORM과 모델 (2) | 2019.02.12 |
[Django] Django Rest Framework에서 request 로깅하기 (2) | 2019.02.08 |
댓글