努力在Hibernate中优化N + 1查询

时间:2011-07-11 21:28:50

标签: hibernate optimization orm data-structures query-optimization

我正在努力改进我正在进行的项目的n + 1查询。我使用Hibernate和下面显示的模型,我想表达一个查询来检索与投资组合相关的所有项目,包括每个项目的最后两个价格(给定日期和之前价格的价格)。

enter image description here

示例API:

List<Items> items = findItemsWithLatestTwoPrices(portfolio, latestPriceDate);

目前我使用一个查询来提取与投资组合相关的所有项目,然后我迭代这些项目以查询给定项目的两个最新价格(所以n + 1)。

我尝试使用相关子查询在本机sql中表达这一点,但性能非常糟糕。这个以及每天都有新价格的事实(所以查询变得越来越慢)让我觉得我需要一个不同的模型,但是我很难想出一个合理有效且随时间不变的模型。价格上涨的数量。

我一直在考虑不同的解决方案,包括将价格表示为链表,或使用某种树,但我相信有更好的选择。我错过了一些明显的东西吗是否有人在解决类似问题时提出了良好的解决方案?

我并不关心我使用HQL还是本机SQL,只要性能不错。我也愿意对模型进行更改。

谢谢!

[编辑]

由于我有超过两年的价格数据,并且可以有1000多个项目。投资组合,检索整个图表可能不是一个好主意。此外,我需要按日期随机访问,因此很遗憾将两个价格作为字段存储在该项目上。

4 个答案:

答案 0 :(得分:0)

您应该尝试在一个查询中检索项目和价格。如果您这样做,您可以迭代您的商品和价格,而无需为每个商品选择。那么你的n + 1问题就应该消失了。

例如,您可以在查询中或关联的定义中使用预先提取。

与您对提高价格对象的性能问题有关。也许您可以将两个价格存储在商品类的一个或两个额外字段中。然后你可以随时渴望获取那些额外的字段,如果需要,可以懒得获取你收藏中的旧价格。

答案 1 :(得分:0)

你可以试试几个选项

  1. 由于您的价格是基于日期的,因此您可以查看按月对数据进行分区。这将大大有助于您的查询,因为价格查找的记录数量将大大减少,而不是查看整个2年的价格。在此之后尝试SQL查询。另外,请运行说明以确保您正在使用正确的索引等。
  2. 您是否考虑过缓存(例如:Memcache)?您可以预先加载当前和现在的商品价格。以前的价格要缓存。然后你可以获取投资组合,项目&amp;查找缓存的价格应该非常快。

答案 2 :(得分:0)

不确定我是否抓住了你所有的担忧,但就像你可能想到的那样,Hibernate没有简单的解决方案。它将归结为您对域的建模。我认为你最好把正常案例和特例分开。您可以在普通域中对它们进行建模,或者对特殊情况使用特殊表示。

要获取n个最新奖品,您是否尝试在关系中设置批量大小?使关系有序(最新的),然后将批量大小设置为类似10.这将使Hibernate查询10行和10行,并且使用外键和订单列上的索引它应该在大多数情况下执行例。

在我看来,你可以保持额外的关系以及整套关系。不要害怕明确地模拟像“上个月价格”这样的重要关系,即使它是重复数据。在大多数情况下,应该可以避免DB中的重复。

对于基于日期的随机访问,听起来你最好通过自定义查询而不是通过域模型访问,如果它们太慢考虑使用二级缓存,但我猜你的访问权限模式不会从中受益很多。

答案 3 :(得分:0)

如果您正在使用Postgre或Oracle,那么当您加入Postgre或Oracle时,可以轻松地对这些价格使用analytic / windowing function,并检索前两个值。只要ORDER BY的列被编入索引,就应该提供足够好的性能。

P.S。下次,如果您说您正在考虑使用本机SQL - 请添加数据库供应商/版本。