[TIL]Django : 장고ORM n+1 문제

은경·2022년 1월 17일

[Python / Django]

목록 보기
1/5

📌 ORM


ORM이란❓

Object Relation Mapper
객체(Object)와 관계형 데이터베이스(Relational)을 연결(Mapping)해 주는 것을 의미.

데이터베이스의 테이블을 객체(Object)와 연결하여 테이블에 CRUD를 할 때, SQL 쿼리문을 사용하지 않고도 데이터베이스의 데이터를 다룰 수 있게 해줌.

Python 외에도 JAVA, C++ 등 다른 언어에도 존재.

장점으로는

  • 쿼리문을 작성하여 데이터베이스를 조작하는 것보다 더 효율적이고 가독성 및 유지 보수에 적합한 코드를 만들 수 있다.
  • 객체 지향적인 코드 작성으로 더 직관적임.
  • 데이터베이스 관리시스템(DBMS)에 덜 종속됨.

단점은

  • 복잡한 쿼리문의 경우 오히려 SQL문 사용이 직관적이면서 효율적일 수 있음.
  • ORM이 모든 걸 해결해줄 수 없다. ORM 만으로는 완벽한 서비스 구현이 어렵다.

장고에서는 자주 사용했던 .filter(), .all(), .get() 등을 예시로 들 수 있다.

📌 n+1 Problem


Django ORM은 Lazy-Loading(지연 로딩)방식을 사용.
ORM에서 명령을 실행할 때마다 데이터베이스에서 데이터를 가져오는 것이 아닌,
모든 명령 처리가 끝나고 실제 데이터를 불러올 때 데이터베이스에 쿼리를 실행하는 방식.

n+1 문제란 성능 이슈를 야기한다.

  • 한번의 ORM 호출로 n개의 모델을 가져온 뒤 n개의 모델을 순회-> 각 모델의 관계 모델에 접근하면서 DB에 또다시 호출.
  • 즉 쿼리 1번으로 N건을 가져왔는데, 관련 컬럼을 얻기 위해 쿼리를 N번 추가 수행하는 문제.
  • DB쿼리 수행비용(횟수)이 크기 때문에, Eager loading 등의 방법으로 해결하는 것이 권장된다.

    Eager loading (즉시 로딩)
    로딩시 참조해야 하는 정보를 미리 명시해서 N+1 쿼리 문제의 해결을 통해 성능 향상 가능, 지연 로딩의 반대 개념

📌 Django ORM 에서 Eager Loading 사용법


select_related, prefetch_related 함수를 이용해 DB에 접근하는 횟수를 줄일 수 있다.
하나의 QuerySet을 가져올 때, 미리 related objects들까지 다 불러오고 (eager loading) SQL문이 캐시에 저장되기 때문에 쿼리의 개수를 줄인다.

📌 select_releated()

  • SQL의 JOIN을 사용, 데이터를 즉시 로딩 (eager loading)
  • single-valued relationships 에서만 사용 가능
    • one-to-one (1:1)
    • many-to-one(1:n) 관계에서 n시점
    • foreign key
    • 정참조 에서 사용

📌 prefetch_releated()

  • 추가 쿼리를 통해 데이터를 즉시 로딩
  • SQL이 아닌 파이썬 단에서 실행
    • many-to-many (m:n)
    • one-to-many (1:n) 관계에서 1시점
    • foreign-key (사실상 모든 relationships에서 사용 가능)
    • 역참조에서 주로 사용


    자세한 사용법이 잘 정리된 블로그 참고 하기

참고 자료(References)


https://hckcksrl.medium.com/django-n-1-problem-d986b93f5d3e
https://velog.io/@kim6515516/npuls

profile
Python 서버 개발자

0개의 댓글