为什么使用Hibernate进行查询缓存会使查询慢十倍?

时间:2009-05-20 20:24:36

标签: java hibernate caching ejb-3.0

我目前正在尝试使用EJB3作为工作中重大项目的预研。我正在研究的一件事是查询缓存。

我使用JPA注释创建了一个非常简单的域模型,一个@Local业务接口和一个EJB-JAR中的@Stateless实现,在EAR中部署了一个非常简单的webapp来进行一些基本测试。 EAR部署在JBoss 5.0.1默认配置中,无需修改。这非常简单,并按预期工作。

但是,我的最新测试涉及查询缓存,我得到了一些奇怪的结果:

  • 我有一个只映射ID和String值的域类,并且在该特定表中创建了大约10000行
  • 在业务bean中,有一个非常简单的查询,SELECT m FROM MyClass m
  • 没有缓存,平均执行时间约为400毫秒
  • 启用查询缓存(通过查询提示),第一次执行当然需要更长的时间,大约1200毫秒。接下来的执行平均需要3500毫秒!

这让我很困惑,所以我启用了Hibernate的show_sql来查看日志。未缓存,并且在启用缓存的第一次执行时,按预期方式记录了一个SELECT。当我应该获得缓存命中时,Hibernate会为数据库表中的每一行记录一个SELECT。

这肯定会解释执行时间慢,但是有人能告诉我为什么会这样吗?

1 个答案:

答案 0 :(得分:16)

查询缓存的工作方式是它只缓存查询返回的对象的 ID 。因此,您的初始SELECT语句可能会返回所有对象,Hibernate会将它们返回给您并记住ID。

然而,下次发出查询时,Hibernate会浏览ID列表并意识到它需要实现实际数据。所以它返回到数据库以获得其余的。并且它每行执行一次SELECT,这正是您所看到的。

现在,在您认为“此功能明显被破坏”之前,它的工作原理是查询缓存旨在与二级缓存协同工作。如果在第一次查询后对象存储在L2缓存中,那么Hibernate将在那里查找以满足每个ID请求。

我强烈建议您选择 Java Persistence with Hibernate 这本书来了解更多相关信息。第13章特别介绍了优化查询以及如何有效地使用缓存。