YUDA't

사이트에서 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 정도로 줄어들었다.