我正在阅读一些hibernate教程并且遇到了default_batch_fetch_size。阅读关于“Can Hibernate be used in performance sensitive applications?”的专家评论清楚地解释了重要性,但我试图理解为什么链接中使用的推荐值4,8,16或32。
关心塔伦
答案 0 :(得分:7)
我们在制作中使用hibernate.default_batch_fetch_size = 100
。因此,在某些情况下,我们有3个查询而不是300个,所以这对我们的数据库来说是一个很好的性能提升。
答案 1 :(得分:6)
<强>要点:强>
启用批量提取时,Hibernate会准备很多查询:这些查询占用了大量内存,无法进行查询。批量大小为1000将占用150 Mo的RAM。
因此,一般批量较小(如10,20或40)是最好的,只需使用@BatchSize注释为特定集合设置更大的批量大小。
详情:
此处解释了获取批量大小Understanding @BatchSize in Hibernate,“hibernate.default_batch_fetch_size”是一般参数,“@ BatchSize”注释允许覆盖特定关联的常规参数。
但这些解释并没有真正回答“为什么官方文件推荐价值观4,8或16”的问题?显然,现代数据库可以在IN子句中处理超过16个值的查询,并且在IN子句中使用1000个值进行查询将允许执行更少的查询,从而允许更好的性能...所以为什么不设置1000作为批量化?
我做到了,我把1024作为batchsize,答案很快就出现了:tomcat服务器需要花费更多的时间来启动,在调试日志中我可以看到许多与“静态选择实体......”相关的行。
Hibernate准备了数以千计的静态查询,这里是实体日志的一部分:
...
Static select for entity Profile [PESSIMISTIC_READ]: select xxx_ with (holdlock, rowlock ) where id in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Static select for entity Profile [PESSIMISTIC_READ]: select xxx_ with (holdlock, rowlock ) where id in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Static select for entity Profile [PESSIMISTIC_READ]: select xxx_ with (holdlock, rowlock ) where id in (?, ?, ?, ?, ?, ?, ?, ?, ?)
Static select for entity Profile [PESSIMISTIC_READ]: select xxx_ with (holdlock, rowlock ) where id in (?, ?, ?, ?, ?, ?, ?, ?)
Static select for entity Profile [PESSIMISTIC_READ]: select xxx_ with (holdlock, rowlock ) where id in (?, ?, ?, ?, ?, ?, ?)
Static select for entity Profile [PESSIMISTIC_READ]: select xxx_ with (holdlock, rowlock ) where id in (?, ?, ?, ?, ?, ?)
Static select for entity Profile [PESSIMISTIC_READ]: select xxx_ with (holdlock, rowlock ) where id in (?, ?, ?, ?, ?)
Static select for entity Profile [PESSIMISTIC_READ]: select xxx_ with (holdlock, rowlock ) where id in (?, ?, ?, ?)
Static select for entity Profile [PESSIMISTIC_READ]: select xxx_ with (holdlock, rowlock ) where id in (?, ?, ?)
Static select for entity Profile [PESSIMISTIC_READ]: select xxx_ with (holdlock, rowlock ) where id in (?, ?)
Static select for entity Profile [PESSIMISTIC_READ]: select xxx_ with (holdlock, rowlock ) where id = ?
...
如您所见,Hibernate准备批量提取请求,但不是所有请求。 Hibernate准备所有1,2,3 .... 10个参数的请求,然后只准备一些args等于batchSize /(2 ^ n)的请求。例如,如果batchSize = 120 =&gt; 120,60,30,15,10,9,8,...,2,1,
所以我尝试用不同数量的元素批量提取集合,结果是:
为了获取18个项目,hibernate进行了2个查询:一个包含16个项目,另一个包含2个项目。
为了获取16个项目,hibernate使用16个项目进行了1次查询。
为了获取12个项目,hibernate进行了2个查询:一个包含10个项目,另一个包含2个项目。
Hibernate只使用了启动时准备的语句。
之后,我监控了所有这些准备好的声明的RAM使用情况:
batchSize = 0 =&gt; 94 Mo(这是我的参考)
batchSize = 32 =&gt; 156 Mo(+ 62 Mo与参考)
batchSize = 64 =&gt; 164 Mo(+ 68 Mo与参考)
batchSize = 1000 =&gt; 250 Mo(+156!Mo参考)
(我的项目中等规模,约300个实体)
现在是结论:
的时候了1)批量大小会对启动时间和内存消耗产生很大影响。它不会与batchsize线性扩展,批量大小为80,比批量大小为10倍。
2)Hibernate无法检索任何大小批量的项目集合,它只使用准备好的批量查询。如果设置batchSize = 120,则准备好的查询将是具有120,60,30,15,10,9,8,7,6,5,4,3,2和1个参数的查询。因此,如果您尝试获取包含220个项目的集合,则会触发4个查询:第一个将检索120个项目,第二个60个,第三个30个和第四个10个。
这解释了推荐的batchSizes低的原因。我建议设置一个像20这样的低全局batchSize(20对我来说似乎比16更好,因为它不会生成比16更准备的查询)并且只在需要时设置一个特定的更大的@BatchSize。
(我使用的是Hibernate 5.1)
答案 2 :(得分:2)
关于内存/启动时间的问题。 试试:
<property name="hibernate.batch_fetch_style" value="dynamic" />
只有一个带有“where id =?”的预处理语句,但会话中对同一类型的实体的批量提取是动态构造的,其限制为hibernate.default_batch_fetch_size。