230321
;; 해결 못했다.
JPA + querydsl 사용 도중 문제 상황을 맞딱뜨렸다. 상황은 다음과 같다.
테이블은 세 개다. farm_log(일기) / user(유저) / good(좋아요)
[farm_log에 좋아요를 누른 user] 연관 관계를 good이라는 연관 테이블에 매핑했다.
JPA repository에서 farmLog.findAll()를 호출하면 N+1 문제에 의해 farmLog와 연관된 유저와 좋아요 엔티티의 갯수만큼 추가 쿼리가 나가게 된다. 이를 방지하기 위해 일단 default_batch_size=1000 을 application.properties에 넣어주고 시작했다. 그럼 추가 쿼리가 나가더라도 N번이 아닌 N/1000번이 나갈 것이기 때문이다.
farmLog가 5개, 좋아요를 누른 사람이 아무도 없는 상황에서 farmLog.findAll()을 했을 때 쿼리문이다.
첫번째 줄, in(?, ?, ?, ?, ?)는 이해가 간다. 5개의 farmLog에 포함된 good 기록을 찾는 것이기 때문이다.
근데 그 다음 in(?,?,?,?), in(?,?,?), in(?,?)은 뭐지?? 마지막 ?가 1000번 있는 것은 default_batch_size가 1000이기 때문에 그냥 1개라고 봐도 무방하다.
원인을 몇 분 고민해봤다.
아마 좋아요를 누른 기록이 하나도 없어서 그런 것일듯. farm_log 5개의 good 연관관계를 처리하기 위해서 good 테이블과 farm_log를 join해도 결과는 아무것도 나오지 않는다. 그럼 join한 결과가 없다~하고 넘기면 되는데 hibernate는 그걸 용납하지 못한다. 사실은 연관 엔티티가 존재하지 않는 것인데 아직 영속성 컨텍스트에 올라오지 않았다고 지 멋대로 단정해버리는 것이다 ㄱ-. 그래서 두번째 farm_log를 처리할 때도 join하고, 세번째 farm_log를 처리할 때도 join하고 마지막 5번째 farm_log를 처리할 때도 join을 하는 참사가 일어나버렸다.
이를 확실히 하기 위해 farm_log에 좋아요 기록을 하나 추가해봤다.
그리고 다시 findAll()을 해보면,
역시.. 좋아요 기록이 있는 1개의 farm_log 엔티티를 제외한 나머지 4번의 추가 쿼리가 나갔다.
아마 1개의 좋아요 기록은 가장 위에 batchSize가 5인 쿼리에서 확인이 되었을 것이다. 나머지 4개 farm_log는 연관 엔티티들이 아직 컨텍스트에 안올라왔다고 hibernate가 멋대로 단정해버리는 바람에 이렇게 된 것이고...
결국 good 테이블 쪽을 fetch join해서 일단 상황모면은 했는데..
multiple 1:N 문제처럼 이건 어쩔 수 없는 것일까?