프로젝트 - 6주차(N+1문제)

YoungSun·2026년 2월 12일

N+1 문제에 대해 써보자

1+N 문제

1번 요청을 날렸는데 추가로 N번 나간 상황

왜 이런일이?

친구 3명과 점심을 먹으러 갔다고 가정하자.
총 4명이 앉아 있다.

“감자탕 파스타 4개 주세요.”
주문은 한 번에 끝난 것처럼 보인다.
그런데 웨이터가 다시 묻는다.

“맛은 어떤 맛으로 드릴까요?”
그래서 한 명씩 대답한다.

나는 매운맛
친구 1은 보통맛
친구 2는 보통맛
친구 3은 매운맛
주문은 한 번이었지만
세부 선택은 인원 수만큼 다시 확인했다.

이걸 DB로 바꾼다면

파스타를 주문했다고 생각해보자


주문서 = 주문서Repository.findAll();

이 코드의 의미는
"주문 내역을 가져와라" 이다.

DB에서는 이렇게 나간다

주문 목록을 조회하라!
select * from order;

결과 : 파스타 4

근데 우리가 궁금한거

“각 주문은 어떤 맛으로 주문했지?”

코드를 추가해줘야 한다

for (주문서 : 주문내역들) {
    System.out.println(주문서.get메뉴().get맛());
}

결과 :
파스타1- 보통맛
파스타2- 매운맛 ...

DB에서 벌어지는 일

select * from orders;         -- 1번
select * from taste where id=1;  -- 1번
select * from taste where id=2;  -- 1번
select * from taste where id=3;  -- 1번
...

주문서가 N개라면
맛 조회 쿼리가 N번 실행된다.

왜 이런 일이 생길까?

핵심은 이것이다.

주문서.get메뉴().get맛()

이 시점에 ORM은

“아, 이 연관 객체를 실제로 써야 하는구나.”

라고 판단하고 그때 쿼리를 날린다.

이걸 지연 로딩(Lazy Loading) 이라고 한다.

해결책

1.fetch join

처음 주문할 때부터 말하면 된다

“감자탕 파스타 4개 주세요.
그리고 매운맛 2개, 보통맛 2개로 주세요.”

웨이터가 다시 물어볼 필요가 없다.

이미 필요한 정보를 한 번에 다 전달했다.

그런데 여기서 끝이 아니다~?

“그럼 무조건 fetch join 쓰면 됨?"

그건 아니다.

만약 주문에 연관된 정보가 여러 개라면?

“감자탕파스타4개주세요그리고매운맛2개보통맛2개로주시고요결제는KB국민카드로할건데카드번호는804802000015498725812이고유효기간은2609CVC는뒤에세자리인데말해도되나요비밀번호는비밀이긴한데혹시몰라서힌트는제생일이고앞자리는공개가능합니다영수증은이메일로보내주시고리뷰이벤트있으면참여할게요적립도해주세요포인트는통합으로묶어주시고혹시몰라서현금영수증도같이해주세요창가자리비어있으면옮기고싶고물은미지근하게얼음은두개만넣어주시고파스타면은조금덜익혀주시고감자탕고기는살코기많은부위로부탁드립니다아그리고혹시오늘주방휴무는아니죠”

...

전부 join fetch로 가져오면
쿼리가 커지고, 중복 데이터가 늘어나고,
오히려 성능이 더 나빠질 수 있다.

아무튼 fetch join은 한 번에 다 가져오는 전략이다.

2.Batch size

웨이터가 한 명씩 묻는 게 비효율적이라는 걸 깨달았다.

그래서 이렇게 말한다.

“매운맛 드실 분 손 들어주세요.”
“보통맛 드실 분 손 들어주세요.”

그리고 한 번에 정리한다.

“매운맛 37개, 보통맛 63개 맞으시죠?”

이제 확인은 여러 번이 아니라
묶어서 몇 번으로 줄어든다.

단점

그래도 완전한 1번은 아니다.

웨이터가

“매운맛 손!”
“보통맛 손!”
“안 매운맛 손!”
.
.
.

이렇게 몇 번은 묻는다.

즉,

N번이 1번이 되지는 않는다.
하지만 N번이 “몇 번”으로 줄어든다.

우리팀은 DTO 전략을 사용했다
왜냐하면 지금 참조하는 속성이 많아
fetch join을 사용 할 수 없기때문이다...

추후 참조하는 속성 제거 후 fetch join으로 변경하려고 한다

1개의 댓글

comment-user-thumbnail
2026년 2월 19일

기술 세미나를 가지 않아서 n+1 이 무슨 의민가 했는데 예시를 들어서 설명하니깐 더 이해가 잘 되었어요!

답글 달기