【问题标题】:@BatchSize a smart or stupid use?@BatchSize 是聪明的还是愚蠢的用途?
【发布时间】:2016-05-04 02:54:19
【问题描述】:

首先我将解释我是如何理解和使用 @BatchSize 的: @BatchSize是为了批量加载对象的关系,减少对数据库的SQL请求。这对 LAZY @OneToMany 关系特别有用。

然而,它甚至对 LAZY @OneToOne 关系和 @ManyToOne 有用:如果您从数据库加载实体列表并要求加载延迟的 @*ToOne 实体,它将加载即使我只是使用加载列表第一个实体的关系的测试,也可以批量处理实体。

如果有人想测试,请注意:这仅显示实体是否尚未加载:例如,如果您有一个带有经理的用户列表并列出所有用户,当您访问经理时,不会触发任何请求因为它已经加载了。

我在该方法中看到的唯一缺点是,如果您从数据库加载项目列表但只使用其中的一部分。这是一个后过滤操作。

让我们进入重点。

让我们假设我做的一切都很好,永远不要做类似后过滤的操作,即使它让我做原生 SQL 查询或使用 DTO 对象进行多选条件查询等等。

  1. 在仔细考虑使用急切加载/加入并最终选择一个惰性关系之后,我是否可以考虑 @BatchSize 每个惰性关系?
  2. 我是否有兴趣为@BatchSize 寻找足够的价值,或者我可以认为“越大越好”?这将意味着““IN”SQL 运算符中是否有任何数量限制可以使我的请求足够慢以至于不再值得?我使用 Postgres 但如果你有其他 SGBD 的答案,我也很感兴趣。
  3. 可选问题:似乎在课堂上使用@BatchSize 并没有产生很多结果。我仍然需要注释每一个懒惰的关系,是我错过了什么还是没用?

编辑:我的 3 点是我得到了不同的行为。

假设我正在加载与 B 具有 LAZY OneToMany 关系的“A”类实体列表。现在我想打印 B 的所有 creationDate。所以我正在做一个经典的 2 for 循环。

我现在用 BatchSize 注释 B:

  • @OneToMany 未使用 BatchSize 注释:每组 B 在每次迭代中独立加载,无需批处理。所以我对 B 类的注释似乎完全被忽略了。即使我将一个值设置为“两个”并且我在一组中有 6 个条目,我也对该组有一个查询。
    • @OneToMany 已注释:我有已加载批次的特定查询。如果我将批量大小固定为 2,并且我总共有 10 个 B accro,我只会收到 5 个请求:无论我有多少 A。如果我将其设置为 100:我有 1 个查询 B 对象。

PS:我没有考虑任何与 B 相关的查询,这些查询可能会触发以使用 fetch select/subselect 加载 B 字段。

编辑 2:我刚刚发现这篇文章 Why would I not use @BatchSize on every lazy loaded relationship? 虽然我在发布我的问题之前用谷歌搜索并搜索了 SO,但我猜我没有使用正确的词...

但是我添加了一些不同的东西,这可能会导致不同的答案:当我想知道在每个关系上使用 BatchSize 时,它​​是在选择我是否想要急切加载、加入/选择获取或我想要懒惰之后正在加载。

【问题讨论】:

    标签: java hibernate postgresql jpa


    【解决方案1】:
    1. 是的,@BatchSize 旨在与惰性关联一起使用。
    2. Hibernate 将在大多数情况下执行多个语句,即使未初始化的代理/集合的计数小于指定的批处理大小。有关详细信息,请参阅this answer。此外,与较小的查询相比,较轻的查询可能会对系统的整体吞吐量产生积极影响。
    3. 类级别的@BatchSize 意味着实体的指定批量大小将应用于与该实体的所有@*ToOne 惰性关联。请参阅 documentation 中带有 Person 实体的示例。

    您提供的链接问题/答案通常更关注优化和延迟加载的需求。它们当然也适用于此,但它们不仅仅与批量加载有关,这只是可能的方法之一。

    另一个重要的事情与链接答案中提到的预加载有关,这表明如果始终使用某个属性,那么使用预加载可能会获得更好的性能。这对于集合通常不正确,在许多情况下对于一对一关联也是如此。

    例如,假设您有以下实体,当使用A 时,bscs 总是使用。

    public class A {
      @OneToMany
      private Collection<B> bs;
    
      @OneToMany
      private Collection<C> cs;
    }
    

    如果您不在单个查询中加入bscs,显然会遇到 N+1 选择问题。但是,如果您将它们加入到单个查询中,例如:

    select a from A
      left join fetch a.bs
      left join fetch a.cs
    

    然后您在bscs 之间创建完整的笛卡尔积,并在结果集中返回count(a.bs) x count(a.cs)为每个a 读取一个由一个组合成A 的实体及其bscs 的集合。

    在这种情况下,批量获取将是非常理想的,因为您将首先读取As,然后是bs,然后是cs,这会导致更多的查询,但从数据库。此外,单独的查询比使用连接的大查询要简单得多,并且更易于数据库执行和优化。

    【讨论】:

    • 1 - 我想我曾经读过它不是一个很好的做法,这就是为什么我想知道,只要我知道后过滤之类的问题,我就可以随处发送垃圾邮件。 3 - 我的行为有所不同,我编辑了我的问题以获取更多信息。你看看这个好吗?
    • @Walfrat 请查看我编辑的答案。 3) 类级别的@BatchSize 仅适用于与这些实体的一对一关联。 1) 过滤后问题是什么意思?
    • 1- BatchSize 加载一堆实体,但是如果您的 SQL/JPA/HQL,... 查询返回您处理的项目列表,以便从中提取其中的一部分(post-过滤),您将在内存中加载不必要的项目。关于您的编辑,这是我已经知道的,这就是为什么正如我所说,关于批量大小的讨论是在选择延迟加载而不是急切之后进行的。 3-感谢您的精确,我确实错过了一些东西所以:P。但是在您提供的链接中,我没有看到清楚的解释。
    • @Walfrat 不客气。当然,没有适用于每种情况的灵丹妙药,总有可能需要自定义处理的情况。
    • 在阅读了@BatchSize 在课堂级别的含义之后,我仍然不明白它会影响@*ToOne 的关联。例如,如果将@BatchSize 放在Person 类上,它会影响Person 类内的所有@*ToOne 关联,还是影响任何其他类内具有Person 类型的字段上的所有@*ToOne 关联?探索示例后,答案是:second.
    猜你喜欢
    • 2016-07-17
    • 2011-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-14
    • 2012-06-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多