• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

BatchSize, Batch Fetch Size 옵션이 적용되지 않는 문제

22.02.01 18:14 작성 조회수 931

6

안녕하세요 영한님 강의 잘 듣고 있습니다!

해당 강의에서 글로벌전략을 지연로딩 설정후

Order -(one to Many) - OrderItemList -(Many To One)- Item 연관관계의 엔티티에

 

BatchSize, Batch Fetch Size 옵션을 적용해

3계층 깊이를 가진 엔티티 그래프를 조회하면 총 쿼리가 계층별로 하나씩,

3개 날라간다고 이해를 했습니다.

그런데 jdk 11, 스프링 Data Jpa와 mysql 등 약간의 환경 변화후 같은 예제로 테스트해보니

 

1. order 쿼리

2. orderItemList의 N개 쿼리(강의에서는 총 2개)

3. 이후 in절로 묶인 item 쿼리가 위의 N개쿼리때문에 N개

 

총 5개의 쿼리가 날라가는 현상이 발생했습니다.

 

요약하면

 첫 연관 엔티티 orderitem은 batchsize 옵션이 적용되지 않아 N개의 쿼리가 날라가고

 

이후에 배치 옵션이 적용되어 각각 in절로 묶인 item  엔티티 쿼리가 날라가고있습니다.

 

이것저것 조작하다가 서비스단에서 transaction 어노테이션을 제거하니

강의에서처럼 엔티티 그래프 계층별로 한개씩

쿼리가 3개로 바뀌어 날라가는데 이유를 잘 모르겠습니다.

 

transaction(Readonly = true) 일때도 정상적으로 쿼리가 3개 날라가는거보면

 

transaction(Readonly = false) 상황에서만 발생하는 문제같은데 혹시 원인을 알수 있을까요?

 

해당 문제를 고민하는 과정을 블로그에 글로 작성했는데 참조해서 정확한 원인을 알려주시면 정말 감사하겠습니다.

https://www.jiniaslog.co.kr/article/view?articleId=559

 

언제나 양질의 강의 제공해주셔서 정말 감사하고 새해복 많이 받으세요!

 

 

답변 2

·

답변을 작성해보세요.

1

안녕하세요. 최원진님

블로그에 정리해주신 글을 잘 읽어보았습니다.

@Transactional, @Transactional(readOnly)의 동작 방식 차이가 내부에서 flush()를 호출한다는 가정을 세우고, 그것을 코드로 확인해보고 코드로 검증하는 과정이 정말 인상 깊었습니다.

저도 확인해보니 말씀하신 것 처럼 flush() 여부에 따라서 해당 기능이 정상 동작하지 않네요.

저도 정확한 문제의 원인은 모르겠지만, 아마도 하이버네이트가 어떤 내부 문제로 최적화를 못한 것으로 생각됩니다.

관련해서 정확한 원인을 아는분 있으면 답변 부탁드려요.

실무에서는 이처럼 복잡한 조회성 쿼리의 경우 트랜잭션 없이 처리하거나, 트랜잭션을 사용해도 readOnly를 사용하기 때문에, 이 부분이 실제 문제가 되지는 않을 것 같아요.

감사합니다.

Kevin님의 프로필

Kevin

2022.11.05

jmeter로 성능향상 테스트중에 우연히 들어왔네요. 이 강의가 이런 내용을 담고 있었군요.. 시간내서 얼른 들어야겠네요 ...!

0

안녕하세요. 최원진님

전체 프로젝트를 압축해서 구글 드라이브로 공유해서 링크를 남겨주세요.

구글 드라이브 업로드 방법은 다음을 참고해주세요.

https://bit.ly/3fX6ygx

 

주의: 업로드시 링크에 있는 권한 문제 꼭 확인해주세요

 

추가로 다음 내용도 코멘트 부탁드립니다.

1. 실행 방법을 알려주세요.

2. 어떻게 문제를 확인할 수 있는지 자세한 설명을 남겨주세요.

추가로 바로 실행할 수 있도록 H2 버전으로 부탁드립니다.

감사합니다.

최원진님의 프로필

최원진

질문자

2022.02.02

빠른 답변 감사합니다! 구글 드라이브에 해당 예제 프로젝트를 업로드 하였습니다.

https://drive.google.com/file/d/1cREMgjBQgJVgPPpdFNjpWCFl28OUVZML/view?usp=sharing

 

h2 버전으로 데이터베이스를 변경했기때문에 다운받으셔서 바로 실행하시면될거같습니다.

 

실행방법은 포스트맨이나 브라우저 url로 

 http://localhost:8080//api/v1/orders

http://localhost:8080//api/v2/orders

 

두 요청을 비교하시면 되고

 

default_batch_fetch_size: 100

옵션이 켜져있는 상황에서

같은 레포지토리의 메서드를 사용하지만

전자의 경우 서비스단에 @Transactional(readOnly=true), 혹은 애너테이션 없음 

후자의 경우 서비스단에 @Transactional(readOnly=false), 혹은 @Transactional

인 차이점이 존재하며

 

전자는 쿼리가 정상적으로 3개 날라가지만

후자는 쿼리가 N+1 문제때문에 총 5개 날라갑니다.

 

flush 여부에 따라 default batch fetch size 옵션 적용이 오락가락하는 상황으로 보이는데 정확한 원인을 모르겠습니다.