用criteria.list()来判断返回的行数是否具有执行性?

Is it performative to use criteria.list () to determine the number of rows returned?

我有一个 Criteria 对象,用于获取公共列表。但在特定情况下,我想使用相同的 Criteria 对象来仅了解返回的行数。

我的问题是如果我使用:

Integer count = criteria.list().size();

它在性能上与以下内容相同:

criteria.setProjection(Projections.rowCount());
Integet count = (Integer)criteria.uniqueResult()

在几乎 所有 情况下,您的投影通常会优于 list().size() 方法调用。为了理解原因,我们需要强调这两种方法之间的差异。

当您要求 Hibernate 执行 list().size() 时,会发生什么?

  1. 我们在数据库级别向目标 table 发出 select。
  2. 数据库必须从磁盘读取数据页,将结果加载到内存中。这会消耗宝贵的数据库服务器资源,例如 cpu 周期、磁盘 i/o 和内存。
  3. 数据库服务器必须将这些结果流式传输到应用程序服务器。此过程受结果集的行数、宽度和网络连接延迟的影响很大。
  4. 在应用服务器上实例化集合元素,并将每个构造的实例添加到 Hibernate Session 的持久性上下文(1LC)中。这再次消耗内存和 cpu 周期来实例化和存储这些对象。
  5. 如果您的集合元素包含任何急切加载的关联,那么 Hibernate 将再次重复步骤 1 到 4,直到根据获取模式加载对象图。显然,当您只需要对集合元素进行计数时,这是完全没有必要的。
  6. 请求 JVM 给你一个收集计数,虽然不多,但仍然浪费了 cpu 个周期。

当您要求 Hibernate 执行 Projection.rowCount() 时,会发生什么?

  1. 我们在数据库级别向目标 table 发出投影查询。
  2. 而不是数据库需要从磁盘读取数据页,如果您的项目查询只是基于主键和任何索引条件的计数,查询将 return 很快,无论我们是否正在谈论小行或大行 table。
  3. 不是将多行和多列的结果集流式传输回应用程序服务器,而是 returned 得到的只是一个值,即计数。这几乎不消耗任何网络带宽。
  4. 由于我们 return 一个值,Hibernate 几乎没有努力 return 该值。此外,由于它是一个聚合值,我们不会将任何信息放入会话的持久性上下文(1LC)中,因此这里没有不必要的内存消耗。
  5. 不会加载任何关联,因为我们没有 return 个实体。
  6. JVM 不需要计数任何东西,JDBC 结果就是计数。

TLDR:

投影将在数据库服务器和应用程序服务器级别使用更少的 cpu、内存和磁盘 i/o,并且不会受到网络延迟的影响,因为结果是与较大的结果集不同的单个值可能。

虽然我知道人们更喜欢 而不是 过早优化,但我确实认为重要的是,当我们需要资源中的某些东西时,我们实际上要求该资源为我们提供准确的东西我们想要而不是试图间接获得所需的结果。这几乎总是技术债务,您以后必须回来修复。