기본

N+1 문제

초혼 2024. 2. 29. 07:45

A 테이블에서 관계가 맺어진 B 테이블의 내용을 같이 조회하는 경우

쿼리를 통해 원래 의도한 A 테이블의 N개의 레코드를 조회한다(1회 쿼리 실행)

SELECT * FROM A;

 

N개 레코드 각각에 연결된 B 테이블 레코드를 조회한다(N회 쿼리 실행)

SELECT * FROM B WHERE A_id = 0;
SELECT * FROM B WHERE A_id = 1;
...
SELECT * FROM B WHERE A_id = N;

 

1개의 쿼리를 실행했는데 결과적으로 총 N+1개의 쿼리가 실행됨

이를 N+1 문제라고 한다

 

ORM을 사용할 경우 쉽게 발생한다

데이터를 실질적으로 사용할 때 로드하는 Lazy Loading 방식으로 인해 그때그때 조회 작업을 실행해서 N+1 문제가 발생한다

 

이러한 문제가 생기지 않게하기 위해서 A와 B 테이블을 조인한다

SELECT * FROM A LEFT OUTER JOIN B ON A.id = B.A_id

 

ORM마다 제공하는 조인 연산을 미리 사용해서 N+1 문제를 방지할 수 있다

Django ORM의 경우 queryset을 만들 때 select_related, prefetch_related 사용해서 해결할 수 있다

  • select_related
    역참조(외래키를 가지지 않은 클래스에서 외래키를 가진 클래스를 참조하는 경우 )
    DB에서 INNER JOIN으로 실행
  • prefetch_related
    정참조(외래키를 가진 클래스에서 외래키를 가지지 않은 클래스를 참조하는 경우)
    각 관계별로 DB 쿼리를 수행하고 파이썬에서 조인을 수행

Node의 TypeORM에서는 relation 옵션을 사용해서 N+1 문제를 방지할 수 있다