在会话中加载实体后,Hibernate查询速度会急剧下降 [英] Hibernate queries slow down drastically after an entity is loaded in the session

查看:88
本文介绍了在会话中加载实体后,Hibernate查询速度会急剧下降的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  public void testQuerySpeed(){
for(int i = 0; i< ; 1000; i ++){
em.createNativeQuery(SELECT 1)。getResultList();
}
}

在我的机器上运行约750毫秒。考虑到它只是选择一个恒定的整数,但不能接受。在启动我的查询之前,我的问题出现在我的EntityManager会话中载入ANY实体的那一刻:

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

for(int i = 0; i <1000; i ++){
em.createNativeQuery(SELECT 1)。getSingleResult();






em.find()很快,但是运行时间1000个查询增加了十倍以上,达到大约10秒。如果我在 em.find()之后放置 em.clear(),问题就会消失并且运行时可以回到750毫秒。

我在这里使用了本地查询,但是HQL查询也存在问题。看来所有的查询至少需要70毫秒,只要一个实体在EntityManager会话中。



当生成需要n + 1个查询的列表时,这种性能下降实际上让我们受到了伤害。

我测试了最新的Hibernate 3.5 beta,并且有完全相同的问题。有没有人看到这个问题,或者有关如何解决它的任何想法?



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

解决方案

我还必须推荐使用JVM分析器看看时间在哪里。为了确保你没有运行比你想像的更多的SQL,它也可能不会伤害到打开Hibernate Session的SQL语句日志。



首先想到的是Hibernate Session的冲洗行为。你是否明确地在会话中设置了特定的刷新模式?如果没有,那么你会得到自动刷新,这将会做一些检查你会话中的对象的数量,以确定是否有需要被刷新回数据库的内存中的变化(在一个事务中当然是)。



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

  public void testQuerySpeed(){
em.setFlushMode(FlushModeType。承诺); //假设您使用的是JPA注释
CommercialContact contact = em.find(CommercialContact.class,1890871l);

for(int i = 0; i <1000; i ++){
em.createNativeQuery(SELECT 1)。getSingleResult();
}
}

另一个想法是询问是否你可以在一个单独的EntityManager中执行你的批量任务,如果你只是在执行UPDATE或INSERT,那么这个任务可以工作。


I'm using Hibernate EntityManager, and am experiencing a weird slowdown in my Hibernate queries. Take a look at this code:

public void testQuerySpeed() {
    for(int i = 0; i < 1000; i++) {
        em.createNativeQuery("SELECT 1").getResultList();
    }
}

This runs in about 750ms on my machine. Not blazing fast considering it's just selecting a constant integer, but acceptable. My problem arises the moment ANY entities are loaded in my EntityManager session before I launch my query:

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

    for(int i = 0; i < 1000; i++) {
        em.createNativeQuery("SELECT 1").getSingleResult();
    }
}

The em.find() is fast, but the runtime 1000 queries increased more than ten-fold, to about 10 seconds. If I put an em.clear() after the em.find(), the problem goes away again and runtime goes back to 750ms.

I've used a native query here, but the problem exists with HQL queries as well. It seems ALL queries take at least 70ms whenever an entity is in the EntityManager session.

This performance drop is really hurting us when generating lists where n+1 queries are needed.

I've tested the latest Hibernate 3.5 beta, and have the exact same problem. Has anyone seen this problem, or any ideas on how to fix it?

I'm using PostgreSQL 8.3, using resource local transactions (running in Tomcat). Using the built-in connection pool, but using C3P0 made no difference.

解决方案

I also have to recommend using a JVM profiler to look at where the time is going. It also may not hurt to turn on the SQL statement logging for the Hibernate Session just to make sure that you're not running more SQL than you think you are.

The thing that first comes to mind here is the "flushing" behavior of the Hibernate Session. Do you explicitly set a specific flush mode on the Session? If not, then you get "auto" flushing which will do some amount of checking the objects you have in your session to determine whether or not there are changes in memory that need to be "flushed" back to the database (inside of a transaction, of course).

I guess the easiest thing to try first to see if it has any effect is to modify the test code you showed above to specify that you want flushing to occur manually when you commit your database transaction:

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();
    }
}

Another thought I suppose would be to ask whether or not you can perform your bulk tasks in a separate EntityManager, which could work if you're just doing UPDATEs or INSERTs.

这篇关于在会话中加载实体后,Hibernate查询速度会急剧下降的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆