在会话中加载实体后,Hibernate查询速度急剧降低

在会话中加载实体后,Hibernate查询速度急剧降低,hibernate,hql,Hibernate,Hql,我正在使用Hibernate EntityManager,并且在Hibernate查询中遇到了奇怪的减速。请看下面的代码: public void testQuerySpeed() { for(int i = 0; i < 1000; i++) { em.createNativeQuery("SELECT 1").getResultList(); } } public void testQuerySpeed(){ 对于(int i=0;i

我正在使用Hibernate EntityManager,并且在Hibernate查询中遇到了奇怪的减速。请看下面的代码:

public void testQuerySpeed() {
    for(int i = 0; i < 1000; i++) {
        em.createNativeQuery("SELECT 1").getResultList();
    }
}
public void testQuerySpeed(){
对于(int i=0;i<1000;i++){
em.createNativeQuery(“选择1”).getResultList();
}
}
这在我的机器上运行大约750ms。考虑到它只是选择了一个常量整数,所以速度不是很快,但可以接受。在我启动查询之前,在EntityManager会话中加载任何实体时,我的问题就会出现:

public void testQuerySpeed() {
    CommercialContact contact = em.find(CommercialContact.class, 1890871l);

    for(int i = 0; i < 1000; i++) {
        em.createNativeQuery("SELECT 1").getSingleResult();
    }
}
public void testQuerySpeed(){
CommercialContact=em.find(CommercialContact.class,1890871l);
对于(int i=0;i<1000;i++){
em.createNativeQuery(“选择1”).getSingleResult();
}
}
em.find()速度很快,但运行时1000次查询增加了10倍多,达到10秒左右。如果我在
em.find()
之后放置一个
em.clear()
,问题会再次消失,运行时间会回到750ms

我在这里使用了本机查询,但HQL查询也存在问题。似乎只要实体在EntityManager会话中,所有查询都至少需要70毫秒

在生成需要n+1查询的列表时,这种性能下降确实会对我们造成伤害

我已经测试了最新的Hibernate 3.5测试版,并且遇到了完全相同的问题。有没有人见过这个问题,或者对如何解决它有什么想法


我正在使用PostgreSQL 8.3,使用资源本地事务(在Tomcat中运行)。使用内置连接池,但使用C3P0没有任何区别。

我还建议使用JVM探查器来查看时间的走向。为Hibernate会话打开SQL语句日志记录,只是为了确保您运行的SQL没有超出您的想象,这可能也没有什么坏处

首先想到的是Hibernate会话的“刷新”行为。您是否在会话上明确设置了特定的刷新模式?如果没有,那么您将得到“自动”刷新,这将对会话中的对象进行一定量的检查,以确定内存中是否有需要“刷新”回数据库的更改(当然是在事务内部)

我想,首先尝试查看它是否有任何效果的最简单方法是修改上面显示的测试代码,以指定在提交数据库事务时手动进行刷新:

public void testQuerySpeed() {
    em.setFlushMode(FlushModeType.COMMIT); // assuming you're using JPA annotations
    CommercialContact contact = em.find(CommercialContact.class, 1890871l);

    for(int i = 0; i < 1000; i++) {
        em.createNativeQuery("SELECT 1").getSingleResult();
    }
}
public void testQuerySpeed(){
em.setFlushMode(FlushModeType.COMMIT);//假设您使用的是JPA注释
CommercialContact=em.find(CommercialContact.class,1890871l);
对于(int i=0;i<1000;i++){
em.createNativeQuery(“选择1”).getSingleResult();
}
}

我的另一个想法是询问您是否可以在单独的EntityManager中执行批量任务,如果您只是在执行更新或插入,则可以使用EntityManager。

您执行的本机查询没有说明它将涉及什么,因此Hibernate必须(为了一致性)刷新()针对它知道的所有表中的所有数据(并且您的单个find()可能已经获取了不止一个对象,因此它可能不是一个简单的操作)


要对此进行优化,请确保使用SQLQuery.add*方法来定义查询实际执行的操作。在本例中,query.addSynchronizedQuerySpace(“bogustablename”)应该告诉Hibernate此查询只是来自非特定表的标量数据。

我基本上遇到了相同的问题(循环内的查询)。我用JProfiler进行了一次分析验证……我感兴趣的方法的执行耗时572秒,hibernate脏检查耗时457秒(约80%)。太棒了,不是吗?我必须说,我有很多实体由EntityManager管理。如果我在有问题的代码中引入em.flush()/em.clear()或em.setFlushMode(FlushModeType.COMMIT),性能问题就会消失


探查器结果可从

获取。您对其进行了探查吗?大部分时间花在哪里?您是否定义了侦听器/拦截器/回调方法?事实上,在我的代码中,flush模式被设置为AUTO。我已经将flush模式设置为提交我们的报告代码,我们无论如何都不会在那里创建任何实体。这有效地解决了性能问题。奇怪的是,对于一个实体,检查脏的对象大约需要60毫秒。非常感谢您的洞察力!天哪,非常感谢亚历山大和布莱恩德!你们都救了我的命!:)我在这里遇到了完全相同的问题,一个事务包含一个循环,其中包含多个搜索和批量插入/更新。经过一周的算法更改、谷歌搜索和评测,我的性能问题用一个简单的方法解决了:em.setFlushMode(FlushModeType.COMMIT);在此之前,整个过程花费了大约28分钟,95%的时间花在了getResultList()上。之后,只要大约2分钟,一切都会好起来。我想知道为什么jpa/hibernate不选择FlushModeType.COMMIT是EntityManager的默认FlushMode。。。