• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

default_batch_fetch_size 원리 질문입니다.

22.07.13 14:39 작성 조회수 316

1

안녕하세요. batch size에 관해서 질문드립니다.

예를들어, 강의처럼 member와 order엔티티로 하겠습니다. (연간관계는 일대다)

batchsize=3인 상태이구용

 

member.orders는 lazy상태이고, db에는 member1~6까지 6개가 들어있다고 가정하겠습니다. (기본키id도 1~6)

 

jpql: select m from Member m  의 결과로는

List<Member> results 이고, size = 6인객체가 오겠네요

 

results.foreach(m -> m.getOrders().size))  이런식으로  results를 전체순환하면서 사용하는게 아닌 아래처럼 사용하면

results.get(3).getOrders().size()
results.get(5).getOrders().size()

in절에는 get3과 5에 해당하는 외래키 id가 4, 6 두개가 나갈것으로 예상했는데, 쿼리를 보니 4, 5, 6 이렇게 나가더라구요.

results.get(3).getOrders().size() 이렇게만 해도 in절에 4 하나만 나가는게 아니라 위와 동일하게 4, 5, 6 으로 되고..

 

results.get(0).getOrders().size()으로 하게 되면 1,2,3 으로,

results.get(5).getOrders().size()으로 하게되면 6,5,4로 되더라구요.

 

그래서 일단 "초기화 안된 콜렉션 타입의 proxy를 실제 db에서 조회하려고 할때는, 무조건 batchsize에 설정된 사이즈만큼 동시에 읽어오고, 엔티티화해서 영속성컨텍스트에 미리 올려놓는다"  라고 생각하려 합니당

 

제가 궁금한 점은 in절로 내보내야할 id들을 가져오는 과정입니다. 

orders는 member의 콜렉션 프록시 이므로(=orders테이블에 memberid가 외래키)
영속성컨텍스트에 이미 로딩되어있는 member엔티티들의 키를 대상으로 in절로 내보낼 id들을 찾아온다 라고 생각하면 맞을까요?

 

제일 의문이었던게 results.get(5).getOrders().size()를 했을때 in절에 6,7,8이 아니라 자동으로 6,5,4로 되는것이 궁금했습니다. 어떻게 6번이 마지막인지 알고 범위내의 in절을 생성하는지..

 

em.detach(members.get(1)) 을 한 상태에서

results.get(0).getOrders().size() 하게 되면 1,3,4 로 나가는것을 보아 영속성 컨텍스트에 존재하는 엔티티를 참조하는게 맞는것 같다는 생각인데 확실치 않아서 문의드립니다.

(더 정확히는, 영속성 컨텍스트에 있으면서 proxy가 초기화 되지 않은 상태인 것들을 대상으로 in절에 보낼 id생성인듯 합니다

 

시나리오 ->

results.get(0).getOrders().size()를 할 경우

  1. 프록시 사용 코드에서 (.size())프록시가 초기화 되지 않은 상태임을 확인.
  2. batchsize=3옵션이 있음.
  3. sql을 만들기 위해 in절로 내보낼 값들도 만들어야 함.
  4. results.get(0)의 반환타입이 Member임(= 프록시를 담고있는 객체가 Member)
  5. 그러므로 영속성컨텍스트에 로딩되어 있는 Member타입의 엔티티들을 찾아 id를 모아와야 함.
  6. 실제 member엔티티내의 orders프록시 객체가 초기화 되어 있는지 확인
  7. 초기화 되어있지 않은 것들만 골라 in절에 해당하는 값을 만들어서 db에 쿼리날림.

)

 

감사합니다!

답변 1

답변을 작성해보세요.

2

안녕하세요. 이용조님

생각하신 내용들이 대부분 맞을꺼에요. 추가로 하이버네이트가 내부에서 다양하게 계산하고 최적화 하는 알고리즘들이 들어갑니다. (다음을 참고해주세요)

https://www.inflearn.com/questions/34469

감사합니다.