【问题标题】:Struggling to optimize N+1 query in Hibernate努力优化 Hibernate 中的 N+1 查询
【发布时间】:2011-07-26 20:11:12
【问题描述】:

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

示例 API:

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

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

我尝试使用相关子查询在本机 sql 中表达这一点,但性能很糟糕。这一点以及每天都有新价格(因此查询变得越来越慢)的事实让我认为我需要一个不同的模型,但我正在努力想出一个合理有效且随着时间推移保持不变的模型价格上涨的数量。

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

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

谢谢!

[编辑]

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

【问题讨论】:

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


    【解决方案1】:

    不确定我是否能解决您的所有顾虑,但正如您可能已经想到的那样,使用 Hibernate 并没有简单的解决方案。这将归结为您对域的建模。我认为您最好将正常情况和特殊情况分开。您可以在您的正常域中对它们进行建模,或者对特殊情况使用特殊表示。

    为了获取最新的 n 个奖品,您是否尝试过在关系上设置批量大小?使关系有序(最新在顶部),然后将批量大小设置为 10 之类的值。这将使 Hibernate 查询 10 和 10 行,并且在外键和 order 列上使用索引,它应该在大多数情况下执行正常案例。

    在我看来,你也可以保持额外的关系以及整个系列。不要害怕明确地建模重要的关系,比如“上个月的价格”,即使这会是重复的数据。在大多数情况下,应该可以避免数据库中的重复。

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

    【讨论】:

      【解决方案2】:

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

      例如,您可以在查询中或关联定义中使用急切获取。

      与您对提高价格对象的性能问题有关。也许您可以将两个最新价格存储在项目类别的一两个额外字段中。然后,如果需要,您总是可以急切地获取那些额外的字段并懒惰地获取集合中的旧价格。

      【讨论】:

      • 您好,感谢您的回答。我对获取整个图表有一些保留意见。由于每天都有价格,并且可能有多达 1000 多个项目 pr 组合,如果您有两年的价格(就像我们一样),这意味着检索和实例化 73000 个对象。我已经编辑了我的问题以包含数字。至于为两个价格使用一个字段,只有在您始终使用每日价格时才有用,但我需要按日期随机访问。
      • 也许您可以先加载投资组合中的所有项目,然后加载所需日期的所有价格(在独立的第二个查询中)。之后,您可以将项目与内存中的价格进行匹配。这样做,您可以避免 n+1 负载。除此之外,除了急切加载整个图表之外,我没有看到其他选项。
      【解决方案3】:

      您可以尝试几个选项

      1. 由于您的价格是基于日期的,您可以查看按月对数据库上的数据进行分区。这将极大地帮助您的查询,因为价格查询的记录数量将大大减少,而不是查看整个 2 年的价格。在此之后尝试 SQL 查询。还要运行解释以确保您点击正确的索引等。
      2. 您是否考虑过缓存(例如:Memcache)?您可以将当前和以前价格的商品价格预加载到缓存中。然后,您可以快速获取价格的投资组合、项目和查找缓存。

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-07-21
          • 2016-01-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多