java - @BatchSize 是聪明还是愚蠢的使用?

标签 java hibernate postgresql jpa

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

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

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

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

那么让我们进入重点。

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

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

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

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

我现在用 BatchSize 注释了 B :

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

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

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

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

最佳答案

  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) 结果集中的行 for each a 逐一读取并组装成 A 的实体及其bscs 的集合。

在这种情况下,批量获取是最佳选择,因为您将首先读取 As,然后是 bs,然后是 cs,结果是更多查询,但从数据库传输的数据总量要少得多。此外,单独的查询比具有连接的大查询简单得多,并且数据库更容易执行和优化。

关于java - @BatchSize 是聪明还是愚蠢的使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35032559/

相关文章:

java - Caused by : java. sql.SQLException: 列索引无效

java - Hibernate Entity getter 中的 LazyInitializationException

sql - 创建更新 View sql错误的规则

java - 如何仅从子元素获取文本 - Webdriver - Java

java - 如何找出 JPA @Entity 中列的长度?

java hibernate ' '中的未知列 'field list'

java - 使用 JDBC 获取多个结果集不起作用

postgresql - 在同一行 Postgres 中使用来自 jSON 的值更新新列

sql - 如何开始一个 DBMS 项目

java - 交互式 JTable