@BatchSize使用聪明还是愚蠢?

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

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

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

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

所以让我们谈谈要点。

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

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

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

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

我现在用BatchSize注释了B:

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

PS:我没有考虑任何与B相关的查询,可能会通过fetch select / subselect来加载B字段。

编辑2:我刚发现这篇文章为什么我不会在每个延迟加载的关系中使用@BatchSize? 虽然我在搜索之前用谷歌搜索并搜索了我的问题,猜猜我没有使用正确的词语……

然而,我正在添加一些不同的东西,可能会导致不同的答案:当我想知道在每个关系上使用BatchSize时,它是在选择我是否需要加入/选择提取或加入/选择提取或如果我想要延迟加载。

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

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

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

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

 public class A { @OneToMany private Collection bs; @OneToMany private Collection cs; } 

如果你不在一个查询中加入它们,那么急切地加载bscs显然会遇到N + 1选择问题。 但是如果你在一个查询中加入它们,例如:

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

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

在这种情况下,批量提取将是非常优化的,因为您首先读取A s,然后读取bs然后读取cs ,从而导致更多查询,但从数据库传输的数据总量要少得多。 此外,单独的查询比具有连接的大查询简单得多,并且数据库更容易执行和优化。