Hibernate session.createCriteria 与 session.get 性能
Posted
技术标签:
【中文标题】Hibernate session.createCriteria 与 session.get 性能【英文标题】:Hibernate session.createCriteria versus session.get performance 【发布时间】:2014-11-13 15:00:08 【问题描述】:我们的开发团队最近开始担心标准和 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 相当的速度?
编辑:我的帖子包含一个重大错误,似乎相同的代码产生了两个不同的统计数据。现在已修复。
【问题讨论】:
我实现了关于这个主题的一些测试,发现 Hibernate 查询执行(尽管使用Session#find
或条件 API)比普通的 JDBC 方法或与 JDBC 对话更多的框架(如 MyBatis)要慢。为此,我们决定将最繁重的查询移至 MyBatis 以加快应用速度。
感谢您的意见 Luiggi!我将研究 MyBatis 的繁重查询。我们已经能够通过在可能的情况下使用缓存关系来提高多个领域的速度,但并非所有查询都可以缓存或关联。
【参考方案1】:
我每次运行以下查询 1001 次。我第一次运行查询时,实体不会被会话缓存,但每次都缓存会话。
你的假设是错误的。使用 Criteria API 时,条件查询不会缓存在持久性上下文中。即使您使用 id 属性,也会执行 SQL 查询。而当使用get
方法时,对象确实被维护在一级缓存中(持久化上下文)。
您可以通过启用show_sql=true
来验证它。对于第一个用例,您将看到一个查询打印输出。对于条件,您将看到 1000 个查询。
第一次热身调用显着变慢的原因是因为必须从池中获取连接/创建,语句可能缓存等。
也就是说,将setCacheable(true)
添加到条件中,您会看到平均时间下降到接近调用get
的水平。
【讨论】:
启用此功能和查询缓存后,我可以将平均查询时间减半。但是,这仍然比 session.get 大 10 倍以上是关于Hibernate session.createCriteria 与 session.get 性能的主要内容,如果未能解决你的问题,请参考以下文章
Spring和Hibernate的注解整合 hibernate3和hibernate4/5的区别