[django] django lazy-loading(지연로딩), eager-loading(즉시로딩) N+1문제 해결

업데이트:

안녕하세요!👋
Django를 통해 join을 하다보면 예상치못하게 쿼리가 느린 경우가 있습니다. 이는 lazy-loading현상에 의해 일어나는 일인데요 이번엔 lazy-loading과 eager-loading에 대해 알아보고 이로인해 쿼리가 느려지는 N+1현상과 해결방법에 대해 적어보려고 합니다

🙏요약

N+1 문제란 무엇이고 왜 생기며 어떻게 해결할지 알아봅시다

  1. lazy-loading과 eager-loading
  2. N+1문제와 해결방법

📝lazy-loading(지연로딩) 과 eager-loading(즉시로딩)

  • lazy-loading (지연로딩) 요즘 사용되는 대부분의 ORM은 지연로딩을 채택하고 있습니다. 지연로딩이랑 실제 db에 쿼리를 날리는 것을 명령어를 받을 때 날리는 것이아니라 실제 객체 내의 원소에 접근할 때 쿼리를 날립니다. 다시말해 함수 내에서 생성된 query를 일일히 모아놧다가 실제 사용될때 한번에 쿼리를 날려서 같은 쿼리를 여러번 날리는 등의 비효율을 효율적으로 바꿔 db접근 시간을 줄이겠다는 의도인데요 이로인해 파생되는 다양한 문제들이 있습니다 가장 유명한 문제인 N+1문제를 알아보도록 하겠습니다

  • eager-loading (즉시로딩) 쿼리가 생성되는 즉시 db에 실제 쿼리를 날려서 객체를 가져오는 것을 의미합니다 복잡할 것 없이 같은 쿼리가 여러번 호출되더라도 그냥 그때그때 바로바로 db에 접근하여 쿼리를 날려서 데이터를 가져오게 됩니다

N+1 문제와 해결방법

  • N+1 문제 N+1문제는 lazy-loading때문에 일어나는 문제인데요. join시 join된 테이블의 정보를 또 불러오는 문제입니다. 1개의 join쿼리를 날렸는데 지연로딩으로인해 먼저 원래 테이블의 원소를 가져오는데 db에 접근해서 쿼리를 날린 후 join된 테이블의 정보를 일일히 n개 가져오는 상황이 벌어지는데요 이는 매우 큰 비효율을 가져오게 됩니다.
    (join시 지연로딩 문제) 원래 테이블 정보 조회 -> 조인된 테이블 정보 일일히 조회

  • 해결방법 fetch join으로 eager-loading 형식으로 쿼리를 날리면 됩니다 django에서는 prefetch-join이라는 명령어를 사용하게 되는데요 이를 통해 즉시로딩 형식으로 쿼리를 바로 날려 쓰든 안쓰든 join된 테이블까지 한번에 가져올 수 있게 됩니다.

Table.objects.prefetch_relative('relative_name').all()

join을 사용할때는 항상 즉시로딩을 사용하도록 합시다!

긴글 봐주셔서 감사합니다 안녕 👋

댓글남기기