Lazy Loading & Caching in ORM

Min-Ho Lee·2020년 11월 18일
5

Learn Django

목록 보기
11/13

Thu_Nov_18
.
.
.
PyCon Korea에서 좋은 영상이 하나 올라왔다.
Django ORM(QuerySet)에 대한 내용이다.

주니어들이 ORM을 공부하면서 놓치기 쉽거나 몰랐던 내용이 많아
공부하는데 정말 도움이 많이 되었다.

ORM의 특징에 대해 다뤄보려고 한다.

Lazy Loading(지연 로딩)

ORM에서는 정말 필요한 시점에만 SQL을 호출하는 특징이 있다.

다시 말해, 정말 필요한 시점이 아니면
QuerySet은 SQL을 호출하지 않는다는 것이다.

예를 들어, 대게로 user의 전체 리스트를 가져올 때
우리는 다음과 같이 코드를 작성한다.

user_list = User.objects.all()

하지만 저 선언은 그저 QuerySet에 불과하다.

저 코드에서는 SQL이 전혀 호출되지 않는다는 것이다.

SQL을 호출하려면 다음과 같이 하면 된다.

user_list = User.objects.all()
list(user_list)

혹은

list(User.objects.all())

이렇게 말이다.

다른 예제를 하나 더 들어보겠다.

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

위 예제에서 SQL 문은 몇 번 호출되었을까?

정답은 1번이다.

실제로 데이터를 얻으려고 한 것은 users 밖에 없기 때문이다.
ORM 이 말 그대로 매핑을 해주는 역할이라 착각하기 쉬운 듯하다.

또 다른 예제이다.

users = User.objects.all()
first_user = users[0]
user_list = list(users)

이런 코드가 있다.
여기서 SQL문은 몇 번 실행 되었을까?

정답은 2번이다.

우리는 첫번째 유저와 모든 유저를 가져오기 위해 User.objects.all()이라는 명령어로 다 가져온듯 싶었지만,
아까 언급했듯이 이 문장은 SQL문을 호출하지 않았다.
아직 데이터를 가져오지 않았다는 것이다.

따라서 첫번째 유저를 가져오기 위해 users[0]라고 했지만, 여기서
LIMIT 1이 걸린 SQL문을 호출했기 때문에 1번,

그리고 모든 유저의 정보를 가져오기 위한 list(users).
즉 SQL문이 한 번더 호출되어 총 2번의 쿼리가 발생했다.

당연히 개발자라면 한번에 가져와 갖고있는 정보로 나눠주면 된다고 생각하지만,
QuerySet에 대해 잘 모른다면 실수할 수 있는 부분이라고 생각한다.

Caching(캐싱)

QuerySet에서 SQL을 호출하면 그 데이터 결과를 가지고 있다.
이것을 QuerySet에서 Result Cache라고 부른다.

아까 위의 예제에서 불필요한 쿼리가 한 번 더 호출되어 총 2번의 쿼리가 발생했다.

이런 문제를 해결하기 위해 QuerySet Caching을 재사용하는 방법을 숙지하고 사용해야 한다.

users = User.objects.all()
first_user = users[0]
user_list = list(users)

이것이 아까의 예제인데, 여기서 순서만 바꾸면 된다.

users = User.objects.all()
user_list = list(users)
first_user = users[0]

여기서 많이 의아해 할 수도 있다.

유저의 모든 정보는 user_list에 담겨있으니
첫 번째 유저의 정보를 가져오려면 user_list[0]이라고 해야 하는 게 아닌가?

일단 2번째 줄에서 모든 유저의 정보를 가져오는 쿼리가 요청되었고,
QuerySet은 그 정보를 캐싱(저장) 하게 된다.

즉, 2번째 줄에 의해 users에는 모든 모든 유저를 담고 있는 QuerySet이 되었다는 것이다.

그래서 users[0]이라는 표현으로 이미 모든 유저 정보를 알고 있는 QuerySet에서 첫 번째 유저를 가져올 수 있는 것이다.

쿼리셋을 호출하는 순서가 바뀌는 것만으로도 QuerySet Caching때문에 발생하는 SQL문이 달라질 수 있다. 라는것.

따라서 아까와 같은 정보를 얻고자 했는데 QuerySet Caching을 이용하여 불필요한 SQL 문이 하나 줄었다.

profile
🐇 Rabbit can take a rest, but 🐢 turtle can't

2개의 댓글

comment-user-thumbnail
2021년 12월 29일

잘 봤습니다~~!

1개의 답글