Java Hibernate session.createCriteria与session.get性能

Java Hibernate session.createCriteria与session.get性能,java,hibernate,caching,jdbc,criteria,Java,Hibernate,Caching,Jdbc,Criteria,我们的开发团队最近开始担心标准和HQL太慢了。我运行了一些基准测试,以了解缓慢的原因 我每次运行1001次以下查询。第一次运行查询时,会话不会缓存该实体,但每次之后都会缓存该实体 Entity e = (Entity) session.get(Entity.class, new EntityID("Composite key value 1", "Composite key value 2")); First call: 80.505875 Average of next 1000

我们的开发团队最近开始担心标准和HQL太慢了。我运行了一些基准测试,以了解缓慢的原因

我每次运行1001次以下查询。第一次运行查询时,会话不会缓存该实体,但每次之后都会缓存该实体

Entity e = (Entity) session.get(Entity.class, new EntityID("Composite key value 1", "Composite key value 2"));

First call: 
    80.505875
Average of next 1000 calls:
    0.045958 ms

Entity e = (Entity) session.createCriteria(Entity.class)
        .add(Restrictions.eq("id", new EntityID("Composite key value 1", "Composite key value 2")))
        .uniqueResult();

First call: 
    91.489098 ms
Average of next 1000 calls:
    0.847434 ms
顺便说一句,HQL中的同一个查询在第一次时花费的时间更长,但在所有后续调用中统计上是等效的

我已经读到,与数据库查询相比,HQL和HQL到SQL转换的标准花费的时间微不足道。根据我的测试,这些翻译似乎比会话所需的时间长18.4倍

0.847434 / 0.045958 = 18.439314
假设有一些实现细节,我预计查询的转换需要0.801476毫秒。这意味着转换步骤需要会话执行时间的17.4倍。使用JDBC,我们可以在0.025368毫秒的时间内运行这些查询。这是一个以前使用ODBC的转换项目,因此我们正在寻找与以前的速度相当的速度。然而,即使使用缓存,我们似乎也无法达到类似的速度

(0.847434 - 0.045958) / 0.045958 = 17.439314
我希望通过使用缓存避免与数据库对话,我们在后续调用中的速度可以与JDBC媲美。标准转换需要一毫秒的时间运行,这正常吗?人们如何通过使用缓存标准达到与JDBC相当的速度

编辑:我的帖子包含一个重大错误,同一个代码产生了两个不同的统计数据。这个问题现在已经解决了

我每次运行1001次以下查询。第一次运行查询时,会话不会缓存实体,但每次之后都会缓存会话

Entity e = (Entity) session.get(Entity.class, new EntityID("Composite key value 1", "Composite key value 2"));

First call: 
    80.505875
Average of next 1000 calls:
    0.045958 ms

Entity e = (Entity) session.createCriteria(Entity.class)
        .add(Restrictions.eq("id", new EntityID("Composite key value 1", "Composite key value 2")))
        .uniqueResult();

First call: 
    91.489098 ms
Average of next 1000 calls:
    0.847434 ms
你的假设是错误的。使用Criteria API时,条件查询不会缓存在持久性上下文中。即使您正在使用id属性,也会执行SQL查询。而当使用
get
方法时,对象实际上是在一级缓存(持久性上下文)中维护的

您可以通过启用
show\u sql=true
来验证它。对于第一个用例,您将看到单个查询打印输出。对于标准,您将看到1000个查询

第一次预热调用的速度要慢得多的原因是,必须从池中获取/创建连接,可能缓存语句等


如果将
setCacheable(true)
添加到条件中,您将看到平均时间下降到接近调用
get
的水平

我实现了一些关于这个主题的测试,并发现Hibernate查询执行(尽管使用了
会话#find
或criteria API)比普通的JDBC方法或像MyBatis这样与JDBC对话更多的框架要慢。为此,我们决定将最繁重的查询转移到MyBatis以加快应用程序的速度。感谢您的输入Luiggi!我会调查一下MyBatis,看看是否有重大疑问。通过尽可能使用缓存关系,我们可以在多个方面提高速度,但并不是所有查询都可以缓存或使其可关联。通过启用缓存和查询缓存,我可以将平均查询时间减半。但是,这仍然比session.get大10倍