Django ORM은 Lazy-loading
라는 특징을 가진다.
이 Lazy loading는 ORM에서 명령마다 DB에 접근해 데이터를 가져오는 방식이 아니고, 명령 처리가 끝나고 실제 데이터를 불러올때 쿼리문을 실행하는 방식이다.
person = Person.objects.all()
흔히 볼 수 있는 위 코드에서 db는 호출되지 않는다.
ps_list = list(person)
불러왔던 person을 list()에 넣었을때 쿼리를 실행하여 DB에 접근하고 데이터를 가져온다.
명령처리가 끝나고 쿼리를 실행하다고 했는데, 정확하게는 특정 시점에서 쿼리를 실행한다.
이 특정 시점은 다음과 같다.
이 Lazy-loading 에서는 N+1 문제라는 성능 문제가 발생한다.
N+1 문제란 외래키를 사용할때 발생하는 문제다.
예를 들어서 그룹에 몇개의 팀이 있고, 팀은 사람으로 구성되고 사람마다 각자 이름이 있다고 생각해보자.
우리는 이 사람들의 이름을 구하려고한다.
# 쿼리를 보내기 전
teams = Team.objects.all()
# 쿼리를 보내는 시점
for team in teams:
print(team.person.name)
처음에 teams를 구할때는 쿼리를 날리지 않는다.
따라서 아래에서 team의 person 정보를 가져오기 위해서 반복횟수만큼 N번의 쿼리를 더 날리게 되는 것이 N+1 문제이다.
N+1 문제를 해결하기 위해서는 Eager Loading
방식을 사용하는 것이다. Eager Loading
는 관련된 데이터를 모두 한번에 가져오는 방식으로, 중복된 데이터를 제거하는데 도움을 준다.
여기서 사용되는 것이 select_related()
, prefetch_related()
이다.