如何使用Hibernate跟踪结果集大小?

10

我正在尝试检测并优化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行,而事实上结果集有1000000行!

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

显然,应用程序开发人员有责任意识到这个问题并不要编写这样的查询。然而,这有时是无意的(并且程度较轻),如果能够通过某种方式对应用程序进行仪器化以识别这些情况,那将是很棒的。

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

有任何建议吗?先谢谢了。


2
你可以在执行查询之前使用 count(*),这样也可以达到同样的效果 :) - Apostolos
query.list().size() 能否给出获取的记录数? - Rat-a-tat-a-tat Ratatouille
进行计数不会使执行时间加倍。它没有从数据库中获取任何实际数据,只是一个包含行数的单个数字结果。对于合理的查询,它不应该造成太多开销。但这些可能不是我们正在讨论的内容;-) - Coffee Monkey
Dhara - query.list().size() 将给出实体的数量(在上面的示例中只有一个!),而不是行数。上面的示例旨在表明两者之间没有简单的关系 - 在这种情况下,一百万行与仅一个实体。 - Dan Foygel
1
C. Monkey - 是的和不是的。例如,如果查询执行表扫描或创建临时表等操作,则会执行这些操作两次。当然,我同意count(*)只传输非常少的数据。 - Dan Foygel
显示剩余2条评论
3个回答

2
有一个名为log4jdbc的项目提供了一个代理JDBC驱动程序,它可以记录SQL(包括绑定参数),以及时间统计、连接打开和关闭事件,甚至ResultSet调用。有几个分支,至少有一个(称为log4jdbc-remix)将结果集记录为表格。
我认为使用jdbc.sqltiming日志记录器应该足以指出问题所在,然后如果需要,您可以通过其他选项进一步深入研究。但是,通过对其进行修改以获取结果集计数似乎是可行的。

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

然而,如果您正在寻找从Java代码计算某些统计信息的任何方法,您应该使用Hibernate统计信息,在某些情况下它们非常有用,确定它们对您没有起作用吗?

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


-1

行数?"select count..."(不像执行两次。计数执行得更快) 列数?反射。玩弄Class.getDeclaredMethods();


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接