[Spring] default_batch_fetch_size 대로 in쿼리가 나가지 않는 이유
개발을 하다가 이상한 상황을 봤다.
default_batch_fetch_size을 1000으로 설정했음에도 불구하고, in절이 62개의 리스트로만 가져오고 나눠서 가져오는 것이다.
버그인가 싶었는데 구글링을 해보니 이유를 찾았다. 역시 킹영한ㄷㄷ
보통 관계형 데이터베이스들은 select * from x where in (?), select * from x where in (?, ?) 같은 preparedstatement는 미리 문법을 파싱해서 최대한 캐싱을 해둔다.
그런데 default_batch_fetch_size가 1000이라면 최대 1000개의 preparedstatement을 준비해야한다.
select * from x where in (?)
select * from x where in (?, ?)
select * from x where in (?, ?, ?)
select * from x where in (?, ?, ? ...)
이렇게 되면 성능이 떨어지기 때문에 Hibernate는 이 문제를 해결하기 위해 2등분을 하며 최적화를 한다.
1000 = 설정값
500 = 1000/2
250 = 500/2
125 = 250/2
62 = 125/2
31 = 62/2
15 = 31/2
7 = 15/2...
이렇게 최적화를 하기 때문에 100개를 셀렉할 때, 62개, 31개, 7개로 끊어가져오는 이유가 여기 있었다.
너무너무 신기하다.
이 방법 외에 그냥 설정한대로 in을 전부하는 방법도 있긴하다.
spring.jpa.properties.hibernate.batch_fetch_style: dynamic
하지만 이방법은 최적화가 되지 않기 때문에 권장치는 않는다고 한다.
때문에 무작정 1000 이렇게 할게 아니라,
본인서비스의 최대 객체양이나 평균양을 고려해서 적정한 수치를 설정하는 것이 좋을 것같다.