【问题标题】:How to track result set size using hibernate?如何使用休眠跟踪结果集大小?
【发布时间】:2013-10-22 20:50:22
【问题描述】:

我正在尝试检测和优化 Java/Hibernate 应用程序中的低效联接。我注意到在某些情况下,由于在结果集中处理连接的方式的性质,线上数据流的效率非常低。

让我举个例子。假设您有一个如下所示的 HQL 查询:

select s from Store s
left join fetch s.items i
left join fetch s.employees e
left join fetch s.customers c
where s.id = :id

(暂时忽略这不是一个智能查询 - 这只是一个简化的示例)。

如果您想象一个给定的商店有 1000 件商品、10 名员工和 100 位客户,您将得到一个包含 1111 个实体的 java 对象树。这可能会让您误以为从数据库返回了大约 1111 行,而实际上结果集有 1,000,000 行!

所有列的存在使情况变得更糟。如果您想象每个表格有 5 列,您可能会想象您得到了大约 5555 个“项目”,而结果集中的单元格数量(行 * 列)实际上是 20,000,000。

显然,应用程序开发人员有责任了解此问题,而不是以这种方式编写查询。但是,这有时会在无意中发生(并且以不太严重的方式),如果能够检测应用程序以某种方式识别这些情况,那就太好了。

但是,我一直无法找到任何方法来计算(从 Java/Hibernate 应用程序中)原始结果集中的行数或列数。 Hibernate 拦截器、Hibernate 事件和 Hibernate 统计信息似乎都无法访问此信息。

有什么建议吗?提前致谢。

【问题讨论】:

  • 在执行此操作之前,您始终可以使用相同的查询,但使用 count(*) :)
  • 是的,这会起作用,但代价是(可能)将每个查询的执行时间加倍,所以这绝对是一个不完美的解决方案 :)
  • can't query.list().size() 给出获取的记录数?
  • 进行计数不会使执行时间加倍。它没有从您的数据库中获取任何实际数据,只是一个包含行数的数字结果。对于明智的查询,它不应该造成那么多开销。但这些可能不是我们在这里讨论的;-)
  • C.猴子 - 是的,不是的。例如,如果查询进行表扫描或创建临时表等,它将执行两次这些操作。当然,我同意通过网络传输的数据很少(*)。

标签: java sql hibernate jdbc orm


【解决方案1】:

有一个名为log4jdbc 的项目提供代理JDBC 驱动程序,它可以记录SQL(添加了绑定参数)以及计时统计信息、连接打开和关闭事件,甚至是ResultSet 调用。有多个分叉,至少有一个(称为log4jdbc-remix)将结果集记录为表格。

我认为使用 jdbc.sqltiming 记录器应该足以指出问题所在,然后如果需要,您可以使用其他选项进行深入分析。但听起来可以破解它来获得结果集计数。

【讨论】:

    【解决方案2】:

    Hibernate 是一个非常复杂的框架。如您所见,与原始 JDBC 相比,它消耗了大量的整体执行时间。而且您的查询不一定会创建 1111 个对象,因为 Hibernate 利用缓存、二级缓存和其他暗技术来代理对象并节省一些内存,这当然取决于配置。

    但是,如果您正在寻找从 Java 代码中计算某些统计信息的方法,您应该使用 Hibernate Statistics,它们在某些情况下非常有用,确定它们不适合您吗?

    QueryStatistics queryStats = stats.getQueryStatistics("from Store s");
    queryStats.getCacheHitCount();
    queryStats.getCacheMissCount();
    queryStats.getCachePutCount();
    queryStats.getExecutionCount();
    queryStats.getExecutionAvgTime();
    queryStats.getExecutionMaxTime();
    queryStats.getExecutionMinTime();
    queryStats.getExecutionRowCount();
    
    SecondLevelCacheStatistics cacheStats = stats.getSecondLevelCacheStatistics("Sale.cache");
    cacheStats.getElementCountInMemory();
    cacheStats.getElementCountOnDisk();
    cacheStats.getEntries();
    cacheStats.getHitCount();
    cacheStats.getMissCount();
    cacheStats.getPutCount();
    cacheStats.getSizeInMemory();
    
    CollectionStatistics collectionStats = stats.getCollectionStatistics("Sale.items");
    collectionStats.getFetchCount();
    collectionStats.getLoadCount();
    collectionStats.getRecreateCount();
    collectionStats.getRemoveCount();
    collectionStats.getUpdateCount();
    

    还有更多选项可供探索http://www.javalobby.org/java/forums/t19807.html

    【讨论】:

      【解决方案3】:

      行数? “选择计数...”(它不像执行两次。计数执行得更快) 列数?反射。摆弄 Class.getDeclaredMethods();

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-08-03
        • 1970-01-01
        • 2014-10-11
        • 2011-05-03
        • 2017-06-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多