8

我在“Manning - Java Persistence with Hibernate”中找到了对批处理获取算法的描述:

真正的批量抓取算法是什么?(...) 想象一下批量大小为 20,总共有 119 个必须分批加载的未初始化代理。在启动时,Hibernate 读取映射元数据并在内部创建 11 个批处理加载器。每个加载器都知道它可以初始化多少个代理:20、10、9、8、7、6、5、4、3、2、1。目标是最小化加载器创建的内存消耗,并创建足够的加载器,每个可以产生可能的批量提取。显然,另一个目标是尽量减少 SQL SELECT 的数量。为了初始化 119 个代理,Hibernate 执行了 7 个批次(您可能期望有 6 个,因为 6 x 20 > 119)。应用的批处理加载器是 5 次 20、1 次 10 和 1 次 9,由 Hibernate 自动选择。

但我仍然不明白它是如何工作的。

  1. 为什么是 11 批装载机?
  2. 为什么批处理加载器可以初始化:20、10、9、8、7、6、5、4、3、2、1 个代理?

如果有人可以提出一步一步的算法...... :)

4

2 回答 2

6

这有助于避免创建大量不同的预准备语句。

每个查询(准备好的语句)都需要被解析,其执行计划需要被数据库计算和缓存。这个过程可能比实际执行已经缓存了语句的查询要昂贵得多。

大量不同的语句可能会导致将其他缓存语句从缓存中清除,从而降低整体应用程序性能。

此外,由于硬解析通常非常昂贵,因此执行多个缓存的预处理语句(包括多个数据库往返)通常比解析和执行一个新语句更快。因此,除了减少不同语句数量的明显好处外,通过执行 11 个缓存语句来检索所有 119 个实体实际上可能比创建和执行包含所有 119 个 id 的单个新实体更快。

正如评论中已经提到的,Hibernate 调用ArrayHelper.getBatchSizes方法来确定给定最大批量大小的批量大小。

于 2015-07-03T08:55:16.990 回答
5

我在网上找不到任何关于 hibernate 如何处理批量加载的信息,但从您的信息来看,可以猜测以下内容:

为什么是 11 批装载机?

在批量大小为 20 的情况下,如果您想最小化任何代理组合所需的加载器数量,基本上有两种选择:

  • 为 1,2,3,4,5,6,7,...20,21,22,23,... N 个未初始化的代理(愚蠢!)或
  • 为 1..9 之间的任何 N 创建一个加载器,然后为batch_size/2(递归)创建更多加载器

示例:对于批量大小 40,您最终会得到 40、20、10、9、8、7、6、5、4、3、2、1 加载器的加载器。

  1. 如果您有 33 个未初始化的代理,您可以使用以下加载程序:20、10、3
  2. 如果您有 119 个未初始化的代理,您可以使用以下加载程序,40(x2), 20, 10, 9
  3. ...

为什么批处理加载器可以初始化:20、10、9、8、7、6、5、4、3、2、1 个代理? 我认为 hibernate 团队选择这个作为加载“常见”数量 N 的未初始化代理和内存消耗所需的加载器数量之间的平衡。可以为 0 和 之间的每个 N 创建一个加载器batch_size,但我怀疑加载器有相当大的内存占用,所以这是一个折衷方案。该算法可以是这样的(有根据的猜测):

  1. n = batch_size; while (n > 10)

    1.1。loader(n); n = n / 2

  2. for n = 0..10 create loader(n)

于 2011-06-09T13:39:17.383 回答