发疯Hibernate分页问题,性能优化!最近写了一个Hibernate分页,之前用游标来实现得到count 总行数..用HQL语
发疯Hibernate分页问题,性能优化!
最近写了一个Hibernate分页,之前用游标来实现得到count 总行数..用HQL语句查询!可是现在问题出现了,但数据达到海量的时候,出现比较慢,现在要进行优化:
1.不能使用游标得到count总行数!
ScrollableResults rs = query.scroll(ScrollMode.SCROLL_INSENSITIVE);
??rs.last();
??return (rs.getRowNumber() + 1);
2.不能使用select count(*) from .....这样要得到count 和list 分布操作很麻烦!查询和count 都要同步!不想两次操作...
假如更改字段都要更改...不想这么做!要公用....
3.不能使用query.list().size()
?int count=query.list().size();
除了这三种方法实现得到count,不知道还能用什么方法去实现!相信javaeye上面大师们应该会出现这样情况吧!遇到过的提提建议...
其中这个removeOrders 和 removeSelect 谁能告诉我一下有什么用处么? 谢谢
还有关于这种海量数据分页的问题,如果不是很在意总数的实事性,是否可以只在第一次查询的时候就算出count,后面的查询只查询内容而不用再次计算count呢?
即第一次查询:
1·查处满足sql条件的所有记录数目 ( count(*) )
2·返回前100条数据
第二次查询(即表示层调用了翻页)
1·查询满足sql条件的第101~200条记录
.....
第n次查询(查找到最后一页)
1·查询满足sql条件的第1000~1200条记录(假设count*的结果是1200)
请问是这样一个过程么 ? 谢谢这个就可以算总数了,ORDER BY 其实不去掉也没事吧。这个就可以算总数了,ORDER BY 其实不去掉也没事吧。
SpringSide就是这么做的,order by不去掉,可能会浪费无谓的排序计算吧。 65 楼 soci 2008-08-20 这个方法不知道多个JOIN TABLE会不会有问题
我的感觉,分页这东西很鸡肋的,还不如像BLOG那样 搞个日历,通过日期访问记录更有意义。
66 楼 iamzealotwang 2008-08-20 能看一下我那个问题么? 谢谢了
67 楼 soci 2008-08-20 iamzealotwang 写道能看一下我那个问题么? 谢谢了
removeOrders 和 removeSelect 方法注释很明白了,前一个去掉ODER BY 后一个去掉 SELECT XXXX
只取中间的from xxx where xx 作为计算COUNT的条件
回到主贴 我还是认为如果海量数据要分页这个需求要灵活些
比如你是新闻网站,最好按日期列出新闻
如果是小说网站,比如给红楼梦分页,那就上一页下一页就可以或者按书的章节分。
如果是论文检索网站,你可以先按年度分页。
总之有很多办法把取总数这个问题绕过去。 68 楼 icewubin 2008-08-20 soci 写道这个方法不知道多个JOIN TABLE会不会有问题
我的感觉,分页这东西很鸡肋的,还不如像BLOG那样 搞个日历,通过日期访问记录更有意义。
join table不会有问题,这个方法我已经在两个项目中用了半年多了。
69 楼 iamzealotwang 2008-08-20 引用
removeOrders 和 removeSelect 方法注释很明白了,前一个去掉ODER BY 后一个去掉 SELECT XXXX
只取中间的from xxx where xx 作为计算COUNT的条件
明白了 谢谢了。
引用
关于这种海量数据分页的问题,如果不是很在意总数的实事性,是否可以只在第一次查询的时候就算出count,后面的查询只查询内容而不用再次计算count呢?
即第一次查询:
1·查处满足sql条件的所有记录数目 ( count(*) )
2·返回前100条数据
第二次查询(即表示层调用了翻页)
1·查询满足sql条件的第101~200条记录
.....
第n次查询(查找到最后一页)
1·查询满足sql条件的第1000~1200条记录(假设count*的结果是1200)
那关于这点,我想的对么? 麻烦您了。
70 楼 soci 2008-08-20 总数保存可以的,很多人这么用。 71 楼 xudong82113 2008-08-20 burt 写道ecsun 写道count(*)一般来说会损失一些性能,加上first和max以后,基本可以不考虑损失的性能,如果实在能count(*)性能不满意
或以改为count(id),这种方式比count(*)性能要好一些
可以拿你的海量数据测一下,就明白了.
同时,如果真的数据量太海量了,count也就意义不大了.这时候可以这么做,比如每一次取出1000条记录,放前台去分页,当然,是不是一次1000条,要看你的访问压力了.
因为频繁访问海量数据,本身对数据库已经是一个很大的压力了,为了每次取得10条一页的数据,去访问一次数据库,划不来,一次多取一点,展现完了再去后台取.
用mssql,4300万的数据,相比select count(*),select count(id)并没有多大提升。
还是4分钟36秒左右。
4300万太过了, 我查看过资料, mysql在单表情况下, 1500万还能保持一个比较高的读写速度, 超过这个数量级, 性能就开始拐点下降了。 72 楼 murainwood 2008-08-21 4300万条?
一张表么?还不拆? 73 楼 icewubin 2008-08-21 murainwood 写道4300万条?
一张表么?还不拆?
银行项目还有百亿级的呢。
表只是个抽象概念,底层可以水平分区或者垂直分区的,上层未必要拆的。
74 楼 nowonder 2008-08-21 mysql的表分区貌似一直都很烂 75 楼 usomething 2008-08-22 同意caohj的说法,我的想法是用spring的AOP拦截Dao的所有方法,一旦方法以remove开头则肯定是删除记录,一旦方法以add开头则是删除记录,hibernate在执行方法的时候会返回一个int值,意义是影响的行数,在Context环境中维护一个static的总数值,一旦AOP拦截器起作用则此static总数值跟着发生变化!说的可能不清楚,我演示一下
Dao某方法:
public int addProduct(List<Product> products){
//具体实现方法,建议使用hibernate的批量插入
}
此方法被Spring拦截到在其拦截器中有一下代码
private static Long total=0L;
public void modifyTotal(int i){
total+=(long)i;
}
如果你记录数实在多得惊人,建议一改变total后立即存入一个文件中或一个字段中! 76 楼 iamzealotwang 2008-08-23 引用
同意caohj的说法,我的想法是用spring的AOP拦截Dao的所有方法,一旦方法以remove开头则肯定是删除记录,一旦方法以add开头则是删除记录,hibernate在执行方法的时候会返回一个int值,意义是影响的行数,在Context环境中维护一个static的总数值,一旦AOP拦截器起作用则此static总数值跟着发生变化!说的可能不清楚,我演示一下
1·remove方法一定是删除,add方法一定是添加。不过Dao的remove和add一定就只删除更改1条记录么?
要是级联咋办?要是saveUpDate呢?我怎么知道他是save了,还是仅仅update了?
这个我觉得应该在数据库触发器里面做文章,那样保险。
2·记录共享 static ,数据量小的时候没有意义,对不?大的时候又需要读取文件。这里否存在进程之间的并发现象?就是操作系统里面读写者问题?
3·对于一般性查询语句,我认为记录总数是没有意义的 是吧?