【问题标题】:Spring&Hibernate performace tunningSpring Hibernate 性能调优
【发布时间】:2022-12-10 16:32:27
【问题描述】:

我有一个像下面代码这样的实体,其中每个短语我都可以有多种不同语言的翻译。

问题是,当我获取翻译时,Hibernate 会为每个短语查询数据库。

因此,如果我有 1000 个翻译,Hibernate 将自动对翻译进行 1 次查询,对短语表进行 1000 次查询。

但与 JOIN 和单个查询相比,这是非常慢的: “SELECT * FROM ad_translations a JOIN ad_phrase ap ON (ap.id = a.id_ad_phrase)”

在这种情况下有哪些选择?我应该使用 Native SQL 还是有更好的方法?

@Entity
@Table(name="ad_translations")
public class Translations implements Serializable  {
    ...
    @ManyToOne
    @JoinColumn(name="id_ad_phrase")
    private Phrase idAdPhrase;

    @ManyToOne
    @JoinColumn(name="id_ad_lang")
    private Lang idAdLang;    
    ...
}

更新: 我在这里阅读了 3 种可能的解决方案https://hackernoon.com/3-ways-to-deal-with-hibernate-n1-problem 但一切似乎都不完美:

  • 第一个解决方案是 NativeSQL,从性能的角度来看,它一定是正确的,但是采用这种方式,我在获取数据时需要编写大量代码,因为我必须手动为 Lang 和短语并根据查询结果填充它们。
  • 第二个解决方案(@BatchSize)涉及太多查询
  • 第三个解决方案(@Fetch(FetchMode.SUBSELECT))在性能方面明显不如第一个

FetchType.Lazy 将无济于事,因为我在 REST 应用程序中使用此实体,所有数据都将在序列化时获取。

我不确定投影如何影响 N+1 问题,似乎它们只有助于使用自定义列数进行选择,但查询数保持不变。

我不知道为什么 Hibernate 没有自动 JOIN 选项,所以我们可以使用第一个解决方案,只需编写很少的代码。

我将选择本机 SQL 选项。

【问题讨论】:

  • 这被称为N+1 problem。有几种方法可以提高性能。 “正确”的取决于具体的用例。我建议研究该主题,然后决定哪种方法最适合给定的用例。

标签: java spring spring-boot hibernate


【解决方案1】:

*ToOne 注释的问题是默认的提取类型是FetchType.EAGER,这意味着,在这种特殊情况下,无论何时提取Translations,它的PhraseLang 也会被提取。

如果将获取类型更改为FetchType.Lazy,则将在执行 getter 时获取关联的实体。请注意,如果您返回 Translations 对象作为响应,那么将在序列化期间获取关联的实体。

作为起点,我建议您使用projections,只检索您需要的属性。当然网上也有很多优化,比如here

【讨论】:

    【解决方案2】:

    我们应该始终首先选择 Native SQL。 但是我们可以在您的情况下使用 ManyToOne 注释 FetchType.LAZY 肯定会减少从数据库中获取信息的时间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-07
      • 1970-01-01
      • 2015-06-07
      • 2021-07-22
      • 2013-05-26
      • 2013-10-17
      • 2018-03-06
      • 2016-06-25
      相关资源
      最近更新 更多