[django] ORM (Lazy Loading과 Caching)

최동혁·2023년 2월 27일
0

Django

목록 보기
10/11

출처 : Django ORM 김성렬씨의 PyCon Korea 2020
이 게시글은 김성렬씨의 강의를 보고 만든 게시글입니다.
제 게시글을 보는것 보다 해당 영상 강의를 듣는게 훨씬 이해가 잘 되실 겁니다.

QuerySet을 통해 알아보는 ORM의 특징

Lazy Loading (지연 로딩)

QuerySet이 필요한 경우

  • ORM에서는 정말 필요한 시점에만 SQL을 호출하는 특징이 있다.
iteration
slicing
repr()
len()
count()
list() 등등
  • 위의 method가 실행될 때 QuerySet이 평가(Evaluate) 된다고 판단. 쿼리셋이 실제 사용되는 것.

  • Django는 QuerySet을 평가(Evaluate)될 때까지 실제로 DB 활동이 발생하지 않기 때문에, DB와 충돌하지 않고 필터링, 슬라이스 등을 할 수 있다.

  • 여기서 말하는 평가(Evaluate)는 실제로 데이터베이스에 도달하는 것을 의미함.

users = User.objects.all()
  • 흔히 착각하는 것이 위의 코드는 실행이 되어도 해당 쿼리문이 실행되지 않는다.
  • 선언된 시점에는 단지 QuerySet에 지나지 않는다.
users = User.objects.all()

user_list = list(users)

  • users라는 QuerySet이 user_list가 되는 시점, 즉 리스트로 묶이는 시점에 SQL이 수행되어서 우리가 원하는 데이터를 가져온다.

위의 예제들로 알 수 있는것은 정말 필요한 시점에만 ORM은 SQL을 호출해서 데이터를 가지고 온다.

QuerySet이 필요하지 않은 경우

users = User.objects.all()
orders = Order.objects.all()
companies = Order.objects.all()

user_list = list(users)

  • 위의 코드는 실제 발생하는 SQL은 users의 SQL만 실행된다.

이로 인한 단점

users = User.objects.all()

first_user = users[0]

user_list = list(users)
  • 일단 위의 코드에서 우리가 바라는 점은 전체 User를 불러와서 users라는 QuerySet에 집어넣은 후, 모든 User가 전부 users에 들어가 있을것이니 첫번째 user는 0번째에 접근해서 빼오고, 이미 불러온 users라는 QuerySet을 list화 시켜서 user_list에 저장하는 것이다.
  • 쉽게 말하면 전체 User를 부르는 SQL을 한번 실행하고, 그 다음에는 이미 QuerySet에 저장했으니 더이상 SQL을 실행하지 않는 것을 기대한다.

하지만 실제 SQL은 그렇지 않다.

  • 위의 사진에서 볼 수 있듯이, first_user 즉 전체 쿼리셋의 0번째에 접근을 한것을 LIMIT 1 SQL 을 이용해서 한명만 따로 받아오고 user_list에 저장하기 위한 코드는 다시 전체 User를 불러오는 SQL을 실행하게 된다.

  • 우리가 기대한 것은 단 한번의 전체 User를 호출하는 SQL인데, LIMIT 1 이라는 쓸데없는 SQL이 실행된 것이다.

Caching을 이용한 해결 방법

QuerySet 캐싱을 재사용하는 방법

users = User.objects.all()

user_list = list(users)

first_user = users[0]
  • 위의 코드는 방금 전 보았던 SQL의 단점을 보여준 코드와 순서만 다르다.
  • first_user를 먼저 호출하는것이 아닌 모든 User를 QuerySet에서 먼저 호출한다.
  • 그렇다면 users라는 QuerySet에는 모든 User의 정보가 캐싱되어 있는 상태이다.
  • 그렇게 되면 전체 User를 불러오는 SQL을 한번 수행한 후, users에 저장되어 있는 정보들을 이용하여 first_user를 SQL을 호출하지 않고 저장할 수 있는 것이다.
profile
항상 성장하는 개발자 최동혁입니다.

0개의 댓글