我有一个java jpa / hibernate应用程序需要获取大量数据才能执行其任务。我遇到了n + 1问题,所以我决定使用hibernate.default_batch_fetch_size(@batchsize)属性来降低所需的sql往返。我尝试了一些值,但是几乎所有尝试过的值都崩溃了。
batchsize:0 - sqls发送:14000 - 持续时间:约1分钟
batchsize:4 - sqls发送:5000 - 持续时间:超过10分钟
batchsize:10 - sqls发送:2700 - 持续时间:约5分钟
batchsize:100 - sqls发送:400 - 持续时间:约1分钟
这是一种“正常”行为吗?如果不是什么可能是错误?
我用log4jdbc记录了生成的sql。我注意到每个批次声明之间的差距大约为100-150毫秒。如果我稍后运行sql,则每个语句的运行时间不超过20毫秒。所以这不是一个与DB(IN语句)相关的问题。
Java:1.6.0_31,Hibernate 3.6.7,DB Postgres 9.1.1,JDBC postgresql-9.1-901.jdbc4.jar
提前致谢
更新 要明确:性能损失是在批量提取期间而不是批量更新/插入
答案 0 :(得分:5)
SessionImpl si = ((SessionImpl) entityManager.getDelegate());
PersistenceContext persistenceContext = si.getPersistenceContext();
persistenceContext.getCollectionEntries();
所以每个集合都会在这个地图中创建一个条目。如果你有很多集合的pojos,就像我的情况一样,它会快速增长。例如,每个32个集合加载了10.000个pojos,你有320.000个集合条目。 Hibernate现在只是迭代遍历map(org.hibernate.engine.BatchFetchQueue.getCollectionBatch(CollectionPersister,Serializable,int,EntityMode))来查找未加载的Collection id以便稍后将它们放在IN子句中。 Hibernate不会将密钥的搜索限制在特定类型的集合中,因此情况会更糟。
我想我必须清理一些集合,并希望hibernate能够更有效地找到更高版本的密钥。
更新: 这个关于hibernate jira的评论对于有同样问题的人来说可能很有趣: https://hibernate.onjira.com/browse/HHH-1775?focusedCommentId=42686&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-42686
更新: 这个问题在hibernate版本中得到了解决:4.1.8