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

Nil*_*sen 8 java caching hibernate 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.

这肯定会解释执行时间慢的问题,但任何人都可以告诉我为什么会这样吗?

Mat*_*nit 17

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

但是,下次发出查询时,Hibernate将浏览ID列表,并意识到它需要实现实际数据.所以它回到数据库来完成其余的工作.它每行做一个SELECT,这正是你所看到的.

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

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