2021년 6월 8일 화요일

[ORM : SQLALCHEMY] N+1 Query Problem

N + 1 이슈란?
쿼리 한번으로 n건의 데이터를 가져와서 원하는 데이터를 얻기 위해 n건의 데이터를 데이터 수 만큼 반복해서 쿼리를 수행하는 문제이다.

ORM에서 가장 흔하게 발생하는 성능 이슈로 언급되며 성능에 큰 영향을 끼치기 때문에 주의 해야한다. 

예제)
python - sqlalchemy
오더 테이블 - 오더 번호, 유저 번호, 주문 상품, ...
유저 테이블 - 유저 번호, 전화번호, 주소, ...

모든 오더와 해당 오더를 주분한 유저의 전화번호를 알고 싶을때

order = db.session.query(Order).all()
for row in order:
    user_number = db.session.query(User.phone).filter(User.id == row.user_id)
    ...

또는

data = db.session.query(Order, User).join(User, Order.user_id == User.id).all()
...

등의 방법으로 데이터를 가져올 것이다.

첫번째 방법이 n개의 오더를 가져와 n번 만큼 for문이 반복하며 유저 테이블을 조회하는
예이다.
"보통 join을 통해 데이터를 가져오지 누가 for문을 이용해 쿼리를 날려 데이터를 가져오나"
 할 수 있지만 코드량이 방대하고, 스파게티 코드이거나 의존성에 의해 해당 이슈가 발생 할 수도 있다.
또한 join의 경우 잘못 사용할 경우 카타시안 곱(n*n)이 발생하여 성능 저하가 일어날 수 있으니 주의해야 한다. 

가끔 join으로 데이터를 가져오기 어려운 경우에는 유저 id: phone 형태의 딕셔너리를 미리 만들어 두어
for row in order:
    user_number = user_dict[row.user_id]
    ...
n+1 -> 2 로 성능을 올릴 수 있다.

댓글 없음:

댓글 쓰기