`
myprincejava
  • 浏览: 31134 次
  • 性别: Icon_minigender_1
  • 来自: 来自太平洋
社区版块
存档分类
最新评论

发疯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上面大师们应该会出现这样情况吧!遇到过的提提建议...

分享到:
评论
36 楼 icewubin 2008-07-27  
lsy 写道
好多回复都跑题了,楼主的问题不是分页,而是如何查询一个海量数据表的总数,Lucas Lee已经给出了很好的答案。


那样的回答是不错,可以把那那种方案的海量级别进一步提高,但是各种“海量”都是有各自极限的,我的意思是思路可以拓展嘛。

再说了,那个方案只是测试了MySql啊,楼主没说什么数据库啊。我前面也提到,SqlServer2000的分页查询就很烂(不是计算总数烂),很多数据库行为不一样的。跑题有时候也没啥不好,只要别跑得太远。

尽管我说了这么多“废话”,Lucas Lee的回复的含金量还是非常非常高的。
35 楼 icewubin 2008-07-27  
tangbo530 写道
count(id) 会好一点点


有时候你的一句hql(sql)不包含id的。
34 楼 tangbo530 2008-07-26  
count(id) 会好一点点
33 楼 zhxp791008 2008-07-26  
1、如果你不用考虑查询条件得到总记录数,用一个触发器,在一个单独的表中记录总记录数。
2、如果总记录数是根据不同的条件得到值不一样,单独整个查询缓存搞定。
3、其它,可能唯有select count(*)。
32 楼 lsy 2008-07-26  
好多回复都跑题了,楼主的问题不是分页,而是如何查询一个海量数据表的总数,Lucas Lee已经给出了很好的答案。
31 楼 spiritfrog 2008-07-26  
icewubin 写道
nihongye 写道
myprincejava 写道
nihongye 写道
很简单,大数据量,不要计算总数

你问题没看明白?现在就是要分页..怎么可能不得到count...

一个只足够翻页的方法,获取多于显示记录数量一的记录集,以此判断是否存在下一页。
计算总数耗费数据库资源,匹配的结果数量一多,建立的索引都浪费了。



总数可以缓存啊,刚才说了5秒缓存性能足够好了。

如果真的是很严重的性能问题,需求就不对,我只是说一个通用的情况,很严重的性能问题往往是需求的问题,而不是技术问题。用户自己真的需要每次翻页都实时的知道当前记录的精确总数么?然后一页一页去翻(1000多页?),这个UI交互模式的需求分析就是有问题的。

开拓思路,例如我如果用LiveGrid(Ext的一个扩展实现,操作方式类似于GoogleReader),总数只会取一次,相当于缓存了总数,你当然可以说这个总数实时性不高,当然没有完美的方案,都是有点缺陷的,要看这些缺陷是否值得去做,当前例子就是“实时性”真的那么重要么?0秒延时和5秒延时区别真的那么大么?很多情况下,1小时延时都被人吹成实时呢。

很多体育比赛实况转播不仅技术上有几秒的延时(卫星传送距离太远需要时间),更多的是故意的5分钟延时,这还不是中国特色,国外也很多的。

记录多的话,确实可以考虑这样, 牺牲一点实时性而已, 对海量数据而言倒能接受。
30 楼 spiritfrog 2008-07-26  
nihongye 写道
myprincejava 写道
nihongye 写道
很简单,大数据量,不要计算总数

你问题没看明白?现在就是要分页..怎么可能不得到count...

一个只足够翻页的方法,获取多于显示记录数量一的记录集,以此判断是否存在下一页。
计算总数耗费数据库资源,匹配的结果数量一多,建立的索引都浪费了。

这样就等于只能上一页和下一页了, 总页数不知道。如果确实页面只需要有上一页和下一页,倒也是不错的方案,避免了求总记录数。

29 楼 zgxzowen 2008-07-26  
icewubin 写道
linkobe 写道
springside的那个分页总数在表关联时是有bug的,比如一个商品有两个价格,这两表关联起来是有两个数据,但返回的却是一个商品,这是实践中发现过的。



有bug么自己改一下呀,SpringSide的bug多了去了,或者说不实际的地方多了去了,但是不影响他的很高的参考价值。


同感,我在项目就用他的分页,但是自己改了好多东西,参考价值和使用价值都很高,有些时候自己想不到的东西,可以参考下开源项目的优秀代码,能给自己很大启发.
28 楼 icewubin 2008-07-26  
linkobe 写道
springside的那个分页总数在表关联时是有bug的,比如一个商品有两个价格,这两表关联起来是有两个数据,但返回的却是一个商品,这是实践中发现过的。



有bug么自己改一下呀,SpringSide的bug多了去了,或者说不实际的地方多了去了,但是不影响他的很高的参考价值。
27 楼 icewubin 2008-07-26  
helyho 写道
建议用存储过程分页吧
hibernate分页多少多会带来相对较大的性能损失的


例如Oracle的Hibernate方言实现就是非常高效的,充分利用Oracle的特点,不比存储过程慢多少,如果都自己写存储过程,如果有切换数据库的需求就麻烦了。

不过话说回来,SqlServer的方言的分页实现效率是有问题的,强烈建议大家不要使用SqlServer2000做复杂工程。
26 楼 icewubin 2008-07-26  
myprincejava 写道
请问icewubin
  你里面那个 HqlUtils是写一个方法还是?我导入包没有这个?谢谢能告知....


非常不好意思,那个是我自己改写的,拷贝错了,SpringSide2中原文如下:

/**
 * 分页查询函数,使用hql.
 *
 * @param pageNo 页号,从1开始.
 */
public Page pagedQuery(String hql, int pageNo, int pageSize, Object... values) {
	Assert.hasText(hql);
	Assert.isTrue(pageNo >= 1, "pageNo should start from 1");
	// Count查询
	String countQueryString = " select count (*) " + removeSelect(removeOrders(hql));
	List countlist = getHibernateTemplate().find(countQueryString, values);
	long totalCount = (Long) countlist.get(0);

	if (totalCount < 1)
		return new Page();
	// 实际查询返回分页对象
	int startIndex = Page.getStartOfPage(pageNo, pageSize);
	Query query = createQuery(hql, values);
	List list = query.setFirstResult(startIndex).setMaxResults(pageSize).list();

	return new Page(startIndex, totalCount, pageSize, list);
}



仅供参考我的HqlUtils.java中一方法代码如下,其实就是上面一段代码中引用的removeSelect和removeOrders方法:
    /**
     * 去除hql的select 子句
     * @param hql
     * @return hql
     */
    public static String removeSelect(String hql) {
        Assert.hasText(hql);
        int beginPos = hql.toLowerCase().indexOf("from");
        Assert.isTrue(beginPos != -1, " hql : " + hql + " must has a keyword 'from'");
        return hql.substring(beginPos);
    }
    /**
     * 去除hql的orderby 子句
      * @param hql
     * @return hql
     */
    public static String removeOrders(String hql) {
        Assert.hasText(hql);
        Pattern pattern = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*"
            , Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(hql);
        StringBuffer buf = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(buf, "");
        }
        matcher.appendTail(buf);
        return buf.toString();
    }


25 楼 icewubin 2008-07-26  
Lucas Lee 写道
我刚才试了一下,在MySQL5下,select count(*) 和select count(id)是完全一样的。
表里有300万+条记录。
花了0.8秒,但是我用explain查看查询计划时,却发现它没有用primiary的index,于是强制它使用主键索引,结果花费了7秒!
我仔细研究了一下默认时使用的索引,居然是用的一个bit(1)上的索引,这个字段就是一个标志位。

想了一下,估计因为这个索引最小,基于bit(1),而主键是基于int(4)的,并且所有索引都能用于计算count(*),因为总是一条记录对应一个索引元素。

因此有一个小技巧提供给楼主:如果你的表中有类似标志位(比如是否逻辑删除)的字段,那么在其上建立一个索引,会把count(*)的速度提高数倍。当然最好用bit(1)类型,而不是int或char(1)保存标志位,那样会更慢。


不一定的,有些数据库对select count(*)做特殊优化的。
24 楼 icewubin 2008-07-26  
nihongye 写道
myprincejava 写道
nihongye 写道
很简单,大数据量,不要计算总数

你问题没看明白?现在就是要分页..怎么可能不得到count...

一个只足够翻页的方法,获取多于显示记录数量一的记录集,以此判断是否存在下一页。
计算总数耗费数据库资源,匹配的结果数量一多,建立的索引都浪费了。



总数可以缓存啊,刚才说了5秒缓存性能足够好了。

如果真的是很严重的性能问题,需求就不对,我只是说一个通用的情况,很严重的性能问题往往是需求的问题,而不是技术问题。用户自己真的需要每次翻页都实时的知道当前记录的精确总数么?然后一页一页去翻(1000多页?),这个UI交互模式的需求分析就是有问题的。

开拓思路,例如我如果用LiveGrid(Ext的一个扩展实现,操作方式类似于GoogleReader),总数只会取一次,相当于缓存了总数,你当然可以说这个总数实时性不高,当然没有完美的方案,都是有点缺陷的,要看这些缺陷是否值得去做,当前例子就是“实时性”真的那么重要么?0秒延时和5秒延时区别真的那么大么?很多情况下,1小时延时都被人吹成实时呢。

很多体育比赛实况转播不仅技术上有几秒的延时(卫星传送距离太远需要时间),更多的是故意的5分钟延时,这还不是中国特色,国外也很多的。
23 楼 icewubin 2008-07-26  
linux.sir 写道
用IBATIS吧,感觉简单,


ibatis一样要解决分页总数问题。
22 楼 helyho 2008-07-26  
建议用存储过程分页吧
hibernate分页多少多会带来相对较大的性能损失的
21 楼 linux.sir 2008-07-26  
用IBATIS吧,感觉简单,
20 楼 myprincejava 2008-07-26  
nihongye 写道
myprincejava 写道
nihongye 写道
很简单,大数据量,不要计算总数

你问题没看明白?现在就是要分页..怎么可能不得到count...

一个只足够翻页的方法,获取多于显示记录数量一的记录集,以此判断是否存在下一页。
计算总数耗费数据库资源,匹配的结果数量一多,建立的索引都浪费了。

考虑周密...也是不错选择!请看看在第二页我贴的代码...是要用两个对象才能实现得到count and list?还是...?
假如是两个对象HQL,进行查询的时候都需要把传进来的值设置到query.setString(),query1.setString() 这样不是重复操作?有没什么好思路得到值...
19 楼 nihongye 2008-07-26  
myprincejava 写道
nihongye 写道
很简单,大数据量,不要计算总数

你问题没看明白?现在就是要分页..怎么可能不得到count...

一个只足够翻页的方法,获取多于显示记录数量一的记录集,以此判断是否存在下一页。
计算总数耗费数据库资源,匹配的结果数量一多,建立的索引都浪费了。
18 楼 LucasLee 2008-07-26  
我刚才试了一下,在MySQL5下,select count(*) 和select count(id)是完全一样的。
表里有300万+条记录。
花了0.8秒,但是我用explain查看查询计划时,却发现它没有用primiary的index,于是强制它使用主键索引,结果花费了7秒!
我仔细研究了一下默认时使用的索引,居然是用的一个bit(1)上的索引,这个字段就是一个标志位。

想了一下,估计因为这个索引最小,基于bit(1),而主键是基于int(4)的,并且所有索引都能用于计算count(*),因为总是一条记录对应一个索引元素。

因此有一个小技巧提供给楼主:如果你的表中有类似标志位(比如是否逻辑删除)的字段,那么在其上建立一个索引,会把count(*)的速度提高数倍。当然最好用bit(1)类型,而不是int或char(1)保存标志位,那样会更慢。
17 楼 linkobe 2008-07-26  
springside的那个分页总数在表关联时是有bug的,比如一个商品有两个价格,这两表关联起来是有两个数据,但返回的却是一个商品,这是实践中发现过的。

相关推荐

    47-Java性能调优实战.zip

    模块七实战演练场则提供了实际场景下的调优实践,帮助学习者将理论知识转化为实际操作经验,解决真实世界中的性能问题。 最后,结束语部分可能总结了整个调优过程中的经验和教训,强调持续学习和实践的重要性。 综...

    额发疯埃尔法未发生阿萨德sad

    额发疯埃尔法未发生阿萨德sad

    一个让人发疯的小礼物

    标题中的“一个让人发疯的小礼物”似乎暗示着这是一款具有独特特性的软件,它可能在初接触时会带来一些挑战或困惑,但最终会给用户带来惊喜和乐趣。描述中的“最后让人开心的礼物”进一步确认了这款软件的娱乐性质,...

    70年代发疯的时代里最正常的艺术家.docx

    70年代发疯的时代里最正常的艺术家.docx

    QixRemake:406发疯了

    QixRemake是一款基于经典游戏Qix的重制版,而"406发疯了"这个描述可能指的是在游戏开发或者运行过程中遇到的一个特定问题,可能是版本号、错误代码或者是某种特定情况的表现。在Python编程中,这样的描述可能意味着...

    英语小组名称和口号精选.doc

    - "要成功,先发疯,下定决心往前冲!" 这些口号体现了坚持不懈、勇往直前、积极进取的精神。它们鼓励人们克服困难,坚信通过努力可以实现目标。无论是学习小组还是其他类型的团队,这些励志的话语都可以激励成员...

    从 0 开始带你成为消息中间件实战高手.zip

    文件“37 基于MQ实现订单系统的核心流程异步化改造,性能优化完成!”探讨了如何利用MQ来优化订单处理流程,提高系统性能。 接着,我们需要掌握MQ的集群建设和压力测试。文件“34 授人以渔:你们公司的MQ集群做过...

    LegacyFactions:Factions 1.6的高性能维护版本

    所有项目均保持开源状态,因此,如果有人想接管它们,请给我直接发送消息,以便我可以授予您访问该回购协议的权限,或者随意分叉它们-发疯! 大多数项目都足够稳定。 我将来可能会继续这些项目,但目前我也做不到。...

    2021关于高考学校横幅标语大全100句.docx

    2. **积极态度**:“主动的人在每一次忧患中都看到一个机会”,提醒学生面对困难时要积极寻找解决问题的办法,而不是被问题所困扰。 3. **持之以恒**:“狠抓基础是胜利的基础,持之以恒是胜利的保证”,强调长期...

    Scripts:一些脚本,分叉的,不要让我发疯!

    去做 很好地说明如何使用这些脚本 AddqBittorrentTrackers.sh 该脚本的目的是在qBittorrent torrent中注入木马,可以手动使用,也可以自动与Radarr / Sonarr一起使用。 实际上,由于API,这可以与qBittorrent v4.1 ...

    冰岛政治正确发疯!「Icelandic Political Correctness gone mad!」-crx插件

    用某些冰岛语替换某些冰岛语。 支持语言:English

    OnyX系统维护和配置

    Mac 用久了,也会有各种各样的问题。无用的日志/记录文件占据大量磁盘空间、字体缓存错乱导致界面字体发疯、磁盘权限出错导致文件无法打开等等等等。此时就需要“优化大师”、“超级兔子”之类的软件出马,清理或者...

    caiHongArchive:彩虹学发疯纪实录

    《caiHongArchive: 彩虹学发疯纪实录》 在信息技术领域,我们经常会遇到各种数据存储和传输的需求,而压缩包文件就是其中一种高效的方式。标题中的“caiHongArchive”很可能是一个自定义的或者特定项目的命名,代表...

    初中语文语文论文一个发疯的语文老师的帖子:感悟大师

    在当今教育界,语文教育一直占据着重要的位置。无论是对个人素养的培养,还是对文化传承的使命,语文教学都扮演着不可替代的角色。随着时代的发展,教育方式和理念也在不断创新与演变。在这样的背景下,三位中国语文...

    wenv:一个个人工作流程项目发疯了

    标题 "wenv:一个个人工作流程项目发疯了" 提示我们这可能是一个关于个人工作环境配置的项目,可能是为了优化Linux、Unix或者MacOS等操作系统中的终端体验。描述中的 "发疯了" 可能是指这个项目包含了大量自动化、...

    图像堆栈:获取3D图像文件,将其切成薄片,然后将生成的图像堆栈布置成一个漂亮的小蒙太奇。 添加蒙版和轮廓。 发疯!-matlab开发

    3D阵列,并在优化的网格中布置每个切片。 添加 遮罩和轮廓线可以使您的图像讲故事。 fig = IMAGEST(propertyArray)从中创建图像堆栈 propertyArray 无花果= IMAGEST(propertyArray,dataOptions,plotOptions...

    基于Web的系统的设计与实现

    在实际的Web系统开发中,优化资源使用、提升性能和保持用户体验的流畅性是非常关键的,这可能就是这个表述想要传达的含义。 【标签】"考试系统"表明我们将讨论的是一个特定类型的基于Web的系统,即用于在线考试的...

    ionic框架参考手册中文

    8. **性能优化**:由于混合应用的特点,性能优化是关键。手册会指导如何减少HTTP请求、优化资源加载、利用懒加载和使用IONIC Serve模式进行快速开发调试。 9. **打包与部署**:Ionic应用可以被编译为原生应用,然后...

    备战高考宣传标语.doc

    3. **目标设定**: 标语“要成功,先发疯,下定决心往前冲!”、“有大目标,须有大动作”鼓励设定明确的目标,并愿意付出巨大努力去实现。 4. **团队精神与协作**: “拧成一股绳,搏尽一份力,狠下一条心,共圆一个...

Global site tag (gtag.js) - Google Analytics