JPA에서 N+1 이슈는 과연 문제일까?
- 국비지원 (스파르타)
- 2025. 2. 11. 15:38
이런 생각이 들었다. 과연 N+1문제는 문제인건가?
그냥 쿼리 하나가 증가했을뿐인데 성능에 그리 큰 영향을 주나?
근데 이건 이렇게 단순하게 생각할 문제는 아니다.
쿼리가 하나 증가하는게 문제인게 아니고 그 쿼리가 불필하다는게 문제다.
그러니까 나오면 안되는게 나왔다고 보는거다.
무리에 불청객한명만 있어도 불편한것처럼 불필요한 쿼리가 증가한건 굉장히 불편한 일일것이다.
게다가 한개만 증가한걸로도 성능에도 영향을 줄 수 있다.
일단 생각해야 하는것이 쿼리의 양은 모른다. 쿼리가 긴지 짧은지 전혀 모른다.
쿼리가 무지무지 길다면 쿼리 하나 증가하는건 굉장히 치명적일거라 생각한다.
내가 하고 싶은말은 N+1을 반드시 해결해야 하는건 성능때문이 아니라 생각한다.
그저 불필요한 쿼리가 하나가 더 추가된게 더 큰 문제라 생각한다.
암튼 어떤 상황에서 N+1문제가 언제 발생하는지 생각해보고 그 상황에서 왜 발생하는지에 대해 고민해보자.
JPA에는 2가지 로딩 방식이 있다. 조인으로 데이터를 가져올 때 사용이 되어진다.
그니까 로딩이라는게 데이터를 가져오는게 아닌가 싶다.
조인을 걸면 아무래도 쿼리양이 많아질게 분명하거라 생각한다. 솔직히 조인을 안걸면
저걸 즉시 가져오는지 지연로딩으로 가져오는지 상관없을거 같다. 암튼 조인을 걸어서 데이터를 가져오는 건데
즉시로 가져와야 하나 지연으로 가져와야 하나 그건 고민이네...
즉시라는건 쿼리를 즉시 가져온다는 뜻이구
지연은 쿼리를 나중에 가져온다는 뜻이다.
뭐 뜻만 봤을때는 즉시가 좋아보이지만 개발 세상에서는 지연이 좋다고 알고 있다.
왜냐하면 지연이라는 단어가 쿼리를 한쪽에 미리 쌓아두고 한번에 가져온다는 뜻이다.
어떻게 보면 최적화가 되는것처럼 보인다. 왜냐하면 한쪽에 미리 쌓아두니까 나름 최적화가 되지 않을까?
근데 즉시는 막?가져오니까 문제가 N+1문제가 발생한게 아닌가 싶다.
그러면 어째서 즉시일때 N+1문제가 발생하는걸까?
지피티 한테 물어보니
즉시 로딩(EAGER)은 연관된 엔티티를 한꺼번에 가져오려다가, 추가적인 개별 쿼리가 발생하여 N+1 문제가 생길 수 있음
이라 한다.
그러면
지연로딩으로 fetch를 바꾸면 N+1이 해결이 되나? 그건또 아니라고 한다.
거의 대부분 해결은 된다는 거 같은데 항상은 아니라고 한다.
지연 로딩을 사용할 때도 반복문에서 연관 엔티티를 조회하면 결국 N번 추가 쿼리가 실행될 수 있다.
이를 해결하려면 Fetch Join, EntityGraph, Batch Size 등의 최적화 방법을 활용해야 된다고 한다.