随笔-46  评论-54  文章-0  trackbacks-0

同事在公司论坛里面发的,其实是我接手的一个项目中存在这个问题。
在使用Hibernate分页器时,习惯使用直接把查询语句、页数、分页大小,传给分页器,这样会默认使用last来获取总记录数,效率非常的低。
解决方法,很简单,就是用SQL来count查询条件获得总记录的Query,再给Hibernate分页器(本身就写好了的)。
这样就必须多写几行代码,就是因为自己懒,觉着效果都一样,就简单的写了。
数据量大了以后,就很明显的速度慢下来了。又全部重头改过,很是郁闷。
转载此文,以示提醒!
即使懒得研究Hibernate底层,也要注意它的效率问题。

 

 

我看到一些资料这样说,oracle的jdbc驱动是不支持服务器端的游标的,当你调用resultSet.last()时,jdbc驱动程序会把整个结果集的数据读到内存,然后在内存中进行结果集的遍历。

如果在做分页的时候,用这样的方式获取结果的总记录数:
  rs.last();
  int rowcount = rs.getRow();
在结果集很大的时候,这个性能是相当低下的,并且会用掉很多的内存。

这个问题是昨天在检查人才网的代码时发现的,随着数据增加,原来被掩盖的问题才开始暴露出来。我们用jprofiler对程序进行剖析的情况也间接的证明了上面的说法:1) 连续几次刷新工作列表后,虚拟机的内存被占满了,运行垃圾回收后内存又被释放出来。2) 从页面请求到完成响应,resultSet.last()方法的调用占去了cpu的绝大部分时间。

因为上面提到的分页方法是一种常用的方法,我建议大家考虑一下自己的代码是否存在这样的问题,这对办公系统的稳定运行可能是很重要的。


参考:
http://www.oracle.com/technology/global/cn/sample_code/tech/java/codesnippet/jdbc/rs/CountResult.html
提到了:
如果 ResultSet 非常大,则 resultset.last() 有可能是非常费时的操作,因为它将使用服务器端的更多资源。因此,除非确实需要可滚动结果集,应避免使用这种方法。

http://forum.springframework.org/showthread.php?t=50044&page=2
提到了:
Anyway, if it's a normal behaviour of the oracle driver to keep data in memory when using SCROLLABLE resultset

http://xiongbo.javaeye.com/blog/38481
对几种游标类型做了介绍,并给出了建议

posted on 2008-05-28 11:26 rox 阅读(4156) 评论(4)  编辑  收藏 所属分类: hibernate

评论:
# re: 开发者请注意oracle jdbc的resultSet.last()方法的效率问题【转载】 2008-08-05 20:55 | tykon
谢了。  回复  更多评论
  
# re: 开发者请注意oracle jdbc的resultSet.last()方法的效率问题【转载】 2008-08-20 15:11 | hello
非常好,谢谢  回复  更多评论
  
# re: 开发者请注意oracle jdbc的resultSet.last()方法的效率问题【转载】 2009-03-12 17:27 | javakaifa
解决方法是什么?  回复  更多评论
  
# re: 开发者请注意oracle jdbc的resultSet.last()方法的效率问题【转载】 2009-03-20 12:08 | rox
@javakaifa
HibernatePage
http://www.hibernate.org/248.html

protected static HibernatePage getScrollPageInstanceWithTotalByScroll(Query query, int pageNumber, int pageSize){
...
sp.scrollableResults.last();
sp.totalElements = sp.scrollableResults.getRowNumber();
...
}
追加一个方法,参数中支持把总数作为参数传进来。
protected static HibernatePage getScrollPageInstanceWithTotalByScroll(Query query, Integer totalCount, int pageNumber, int pageSize){
...
if (totalCount != null)
sp.totalElements = totalCount.intValue();
else {
sp.scrollableResults.last();
sp.totalElements = sp.scrollableResults.getRowNumber();
}
...
}
这个totalCount,使用相同查询条件,只是查询中使用count(*)来计算结果,并赋值给totalCount。
也就是说同样一个查询,要做两遍,一个是count,先做,再一个才是查询。  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: