【问题标题】:Is there a way within hibernate to retrieve fast non-blocking row counts?休眠中有没有办法检索快速的非阻塞行数?
【发布时间】:2023-04-05 06:31:01
【问题描述】:

hibernate 生成的以下查询需要 13+ 秒并锁定表:

SELECT COUNT(auditentit0_.audit_id) AS col_0_0_ FROM Audit auditentit0_ WHERE 1=1; 

不断增长的 Microsoft SQL Server 数据库表包含 90+ 百万行。

对于 Microsoft SQL Server,我找到了一种准确的元数据方法,可以非常快速地获取相同的信息。

不过,如果 hibernate 有办法获取这些信息,我宁愿不为 Microsoft sql server 和 oracle(下一个数据库)编写自定义代码。

以下是 Microsoft sql server 的元数据查询示例,该查询准确且几乎是即时的:

SELECT SUM (row_count) FROM sys.dm_db_partition_stats WHERE object_id=OBJECT_ID('huge_audit_table') AND (index_id=0 or index_id=1);

有没有办法让 hibernate 发出类似的表行计数查询?


一个发布的答案表明视图可能是有用的。我正在调查这篇文章,看看它是否可以解决问题:

https://vladmihalcea.com/map-jpa-entity-to-view-or-sql-query-with-hibernate/

【问题讨论】:

  • 1) “锁定表格”到底是什么意思?我以前从未见过 SELECT 查询锁定任何东西。 2)全表扫描看起来不正确,我希望对 PK 列进行快速索引扫描。 3) 为什么 1=1?条件不是必须的。 4) 是 Oracle 还是 MS SQL? 5) 元数据是一个估计,而不是正确的值
  • 为什么需要它?统计结果。永远不会准确。但实际上没有表行计数是准确的——至少在 Oracle 上是这样。读取始终是非阻塞的,因此在读取过程中行数可能会发生变化。
  • @D-Klotz 将标签从 Oracle11g 更改为 MSSQL
  • Oracle 中的选择计数不会阻塞,元数据字典不同。我不认为有这样的解决方案。 gl
  • 在不查看实现细节的情况下,我会考虑创建您自己的视图并将 RDBMS 差异隐藏在视图定义后面的可能性。然后您可以将视图映射到一个简单的 Hibernate 实体。那有意义吗?也可以是存储过程。

标签: java sql sql-server hibernate oracle11g


【解决方案1】:

在休眠中,您应该使用您提供的链接中的投影,以确保它适用于多个 dbms:

protected Long countByCriteria(DetachedCriteria criteria) {
   Criteria crit = criteria.getExecutableCriteria(getSession());
   crit.setProjection(Projections.rowCount());
   return (Long)crit.uniqueResult();
}

你在mysql中使用什么引擎?我从来没有遇到过 MySql 或 Oracle 中的行计数阻塞问题。也许以下链接会对您有所帮助:Any way to select without causing locking in MySQL?

另外,经过快速阅读后,我发现 Sql Server 确实会阻塞计数。

也许您可以使用存储过程或其他机制将问题传递给 dbms。


编辑:

Hibernate 中的投影用于选择要获取的列、用于分组元素的列以及使用内置的聚合函数(sum、count、avg、max、min、countDistinct)。

它可以帮助您保持应用程序与数据库无关。请记住,hibernate 支持大约 30 个数据库。

在您的情况下,您对 mssql 有一个特定问题,因为计数会阻止表优先级准确性。并且使用系统视图非常快,因为您可以得到估计但不是标准的。

您可以将问题封装到依赖于 dbms 的视图或存储过程中。或者,也许您可​​以尝试在休眠状态下使用 NOLOCK 提示或 READ UNCOMMITED (在审计表的计数中,它应该是可以接受的)。

【讨论】:

  • 我不熟悉除了快速谷歌之外的预测。以上对你有什么作用?回想一下,在执行选择计数 () 时,问题出在 microsoft sql server 中。它在(我假设是索引)扫描期间锁定表。上述投影如何绕过它?很糟糕的是,hibernate 没有为 count() 和 ms sql server 提供一些特殊的东西来避免这种情况。
  • 感谢您的信息。 NOLOCK 会有所帮助,但查询仍然需要 13+ 秒,这是不可接受的。我将研究一个“视图”,看看它是否可以隐藏 Microsoft sql server 特定代码。如果可行,我会 +1 并标记为答案。谢谢。
  • 该视图的优点是您可以使用其他 dbms 特定方法来获取行数估计值。在 mysql 中,您可以从 INFORMATION_SCHEMA 或 TABLE STATUS 中获得估计值,但您应该研究误差范围。
  • 为了解决这个特殊问题,我们退后一步并更改了 UI 的功能。通过 UIX 和 UI 开发人员之间的协作,我们同意未过滤的查询不会询问总数。初始屏幕加载将仅显示一个充满数据的页面。 60,000 个控件中的第 1 页将不存在。只有当用户输入特定标准时,总计数才会起作用。这些查询应该非常快。现在......用户仍然可以设置一个与原始问题一样糟糕的查询。它应该是例外而不是常态。
  • 我记得有一次我们遇到了类似的问题,我们所做的就是显示类似“Page 1 - 2 - 3 - 4 - ... - 10 of Many”的内容。不理想,但它避免了这个问题。
【解决方案2】:

为了解决这个特殊问题,我们退后一步并更改了 UI 的功能。通过 UIX 和 UI 开发人员之间的协作,我们同意未过滤的查询不会询问总数。初始屏幕加载将仅显示一个充满数据的页面。 60,000 个控件中的第 1 页将不存在。只有当用户输入特定标准时,总计数才会起作用。这些查询应该非常快。现在......用户仍然可以设置与原始问题一样糟糕的查询。它应该是例外而不是常态。

因此,对于 OP,确实没有可靠的答案。如果您面临此类问题,如果您可以控制 UI 和 API,那么是时候重新考虑解决方案了。想想 google 如何从 UI 角度处理分页。恕我直言,显示“(XX)的第 1 页”的日子已经一去不复返了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-09
    • 2014-07-18
    • 2022-08-24
    • 1970-01-01
    • 1970-01-01
    • 2011-07-15
    • 2012-04-13
    • 1970-01-01
    相关资源
    最近更新 更多