hibernate已实现分页查询,数据量百万以上越往后的数据查询的越慢,怎么解决?

时间:2021-01-17 20:10:08
hibernate已实现分页查询,查询前面的数据速度很快,但查询后面的数据就很慢:

比如我现在是  200,0000 条记录,
页面 是:  首页 上一页 下一页 尾页

点首页或点下一页查询很快,但点尾页就要十几秒才能查询到,此时再点上一页也是需要十几秒才能查询到

也就是说越往后的数据查询的越慢,有什么好的办法能解决此问题?

有没有比较好的方法能显著提升速度?

31 个解决方案

#1


优化数据库,在相关字段上建索引。或者采用分区表之类的。

hib一般也用的是数据库的分页,比如oracle的rownum等,单纯从sql上来说,很难优化了。
200w的数据量,通常查最后几页都需要差不多这个时间(存在order by)。

#2


引用 1 楼 crazylaa 的回复:
优化数据库,在相关字段上建索引。或者采用分区表之类的。

hib一般也用的是数据库的分页,比如oracle的rownum等,单纯从sql上来说,很难优化了。
200w的数据量,通常查最后几页都需要差不多这个时间(存在order by)。

优化数据库
感觉用hibernate做分页  很多小细节要注意的  

#3


优化数据库,在相关字段上建索引。或者采用分区表之类的。 

优化数据库,在相关字段上建索引
我没用过,不知道怎么操作,能否详细说一下?与存储过程相比呢?
我用的是SqlServer2005

#4


引用 3 楼 sw4433 的回复:
优化数据库,在相关字段上建索引。或者采用分区表之类的。

 优化数据库,在相关字段上建索引
 我没用过,不知道怎么操作,能否详细说一下?与存储过程相比呢?
 我用的是SqlServer2005


sqlserver不懂。

把hib生成的sql晒下?看看你有没有索引。。

#5


对了存储过程肯定也跟hib一样是用数据库的分页来做的了。如果sql一样的话,存储过程和hib调用,性能区别不会很大。

#6


Hibernate: select top 10 guestbook0_.id as id0_, guestbook0_.name as name0_, gue
stbook0_.email as email0_, guestbook0_.url as url0_, guestbook0_.title as title0
_, guestbook0_.context as context0_, guestbook0_.time as time0_ from guestBook.d
bo.guestBook guestbook0_ order by guestbook0_.id asc


#7


create index my_index on guestBook(id)

建立索引了速度好象还是一样慢!
是不是在数据库创建了索引就可以了?是否要象存储过程那样引用呢?

#8


关注中

#9


mark

#10


 order  by guestbook0_.id 
ID是主键的话,已经有索引了,你这里又没有where条件可作优化。。。
ID不是主键的话,看看ID上面有没有索引,没有的话,建一个。
create index idx_gbook_id on 表名(列名); --表名指数据库表名,列名指ID。这句话在数据库中做。
你这里没有where条件,一次全取200w排序。。。,从数据库来看,也没有办法分区优化了。。。。

楼主认命吧,或者加内存,加cpu。。。 hibernate已实现分页查询,数据量百万以上越往后的数据查询的越慢,怎么解决?

#11


id为主键,等于有索引了

速度还是很慢,Hinernate 难道只能就这样了?

#12


引用 11 楼 sw4433 的回复:
id为主键,等于有索引了

 速度还是很慢,Hinernate 难道只能就这样了?

没办法,我的机器1G内存,双核,也是只有PK的索引,oracle92数据库,200w数据,有order by,取最后10条也差不多这个时间(sql跟你的一样。。。)

#13


使用hibernate建议配上二级缓存,不然数据量大了,是非常耗性能的,而且你的延迟加载等等都得设置好,和主控,级联,不然极有可能把你的整个数据库给load出来
hibernate做的最好的就是缓存

#14


引用 13 楼 tianwailaifenglove 的回复:
使用hibernate建议配上二级缓存,不然数据量大了,是非常耗性能的,而且你的延迟加载等等都得设置好,和主控,级联,不然极有可能把你的整个数据库给load出来
 hibernate做的最好的就是缓存

哦?二级缓存什么意思?是不是比如我每页要查10条,但是它给我查一百条出来,然后每次翻页就从缓存里面拿啊?如果不是这样的话,难道200w也一次都放内存?
我不懂hib啊,纯粹瞎猜的,不用当真。

#15


引用楼主 sw4433 的回复:
hibernate已实现分页查询,查询前面的数据速度很快,但查询后面的数据就很慢:

比如我现在是200,0000条记录,
页面 是:首页 上一页 下一页 尾页

点首页或点下一页查询很快,但点尾页就要十几秒才能查询到,此时再点上一页也是需要十几秒才能查询到

也就是说越往后的数据查询的越慢,有什么好的办法能解决此问题?

有没有比较好的方法能显著提升速度?

可以从多方面下手:第一,可以为查询的设置索引;第二,优化查询,使用数据库分页(如Oracle的伪列);第三,用数据库存储过程来分页,返回一页的数据,也挺好。

#16


引用 13 楼 tianwailaifenglove 的回复:
使用hibernate建议配上二级缓存,不然数据量大了,是非常耗性能的,而且你的延迟加载等等都得设置好,和主控,级联,不然极有可能把你的整个数据库给load出来
hibernate做的最好的就是缓存


二级缓存 什么个意思?
怎么设置?

#17


也在研究这问题.关注此贴

#18


学习

#19


你项目真大。百w级数据。 

#20


   mark,关注 。。。

#21


jdbc 试试

#22


学习中..

#23


曾经看过一个人问SQL SERVER 2000如何去除伪分页 我才知道 HIBERNATE在SQL SERVER 2000里用的是伪分页  后来SQLSERVER 2005有类似Oracle的分页函数了之后 就可以通过修改数据库方言 让HIBERNATE支持真分页了

http://blog.csdn.net/tdl982324/archive/2008/07/03/2607674.aspx

LZ看这个

#24


引用 6 楼 sw4433 的回复:
Java codeHibernate: select top10 guestbook0_.id as id0_, guestbook0_.name as name0_, gue
stbook0_.email as email0_, guestbook0_.url as url0_, guestbook0_.title as title0
_, guestbook0_.context as context0_, guestbook0_.time as time0_ from guestBook.d
bo.guestBook guestbook0_ order by guestbook0_.id asc


这么写,where条件也没有,建了索引也用不到,每次运行都是从表的起始位置开始一行行扫描,当然越往后越慢了。

#25


	//查找记录
public List getAllGuestBooks(int firstResult,int maxResult){
Session session = this.getSession();
System.out.println("all");
List list = null;;
try {
Query query = session.createQuery("from GuestBook order by id asc"); 
query.setFirstResult(firstResult).setMaxResults(maxResult);
list = query.list();
} catch (HibernateException e) {
e.printStackTrace();
} finally{
session.close();
}
return list;
}

id为主键,我是传的是参数啊query.setFirstResult(firstResult).setMaxResults(maxResult);

#26


想用到id这个索引,sql语句要类似这样: select * from GuestBook where id = ?

select * from GuestBook这样是用不到的。

另外"from GuestBook order by id asc"这句得优化,把order by id asc去掉,id是主键,本身就是排好序的了

#27


引用 26 楼 sunnylyy 的回复:
想用到id这个索引,sql语句要类似这样: select * from GuestBook where id = ?

select * from GuestBook这样是用不到的。

另外"from GuestBook order by id asc"这句得优化,把order by id asc去掉,id是主键,本身就是排好序的了


sql语句我知道,如果是通过别的字段排序,怎么提高效率呢?比如通过name查询,by name desc
query.setFirstResult(firstResult).setMaxResults(maxResult); 
这是设置从哪条数据查,一次查询多少条数据

#28


跟一次查多少条关系不大,界面上强制加查询条件吧,然后用到索引。比如name字段建立索引,查询的时候类似这样:from GuestBook where name like 'AAA%'

order by尽量不要加了。

其实想想,对一个几百万的大表做分页显示,还不加任何查询条件,好象没什么必要。

#29


没有正式用过Hibernate..

但看过Hibernate的源码,,Hibernate 2针对于sqlserver 的分页只是逻辑分页。。

好像Hibernate 3也是逻辑分页。。。

只会在sql数据的时候在上top,只有第一页数据会出现的比较快,,而后翻页是查询出来的数据越来越多,再通过翻动游标返回数据。。。

像我正在用的ibatis也是如此,,,这些orm都唯独不支持sqlserver的物理分页。。

解决办法,,,楼主网上应该一大吧。。。基本上应该重载sqlserver的方言。。。

其实200w的数据也不算多,,,

贴点源码:
orcle:
public String getLimitString(String sql, boolean hasOffset) {
sql = sql.trim();
boolean isForUpdate = false;
if ( sql.toLowerCase().endsWith(" for update") ) {
sql = sql.substring( 0, sql.length()-11 );
isForUpdate = true;
}

StringBuffer pagingSelect = new StringBuffer( sql.length()+100 );
if (hasOffset) {
pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");
}
else {
pagingSelect.append("select * from ( ");
}
pagingSelect.append(sql);
if (hasOffset) {
pagingSelect.append(" ) row_ where rownum <= ?) where rownum_ > ?");
}
else {
pagingSelect.append(" ) where rownum <= ?");
}

if ( isForUpdate ) {
pagingSelect.append( " for update" );
}

return pagingSelect.toString();
}

sqlserver:

public String getLimitString(String querySelect, int offset, int limit) {
if ( offset > 0 ) {
throw new UnsupportedOperationException( "sql server has no offset" );
}
return new StringBuffer( querySelect.length()+8 )
.append(querySelect)
.insert( getAfterSelectInsertPoint(querySelect), " top " + limit )
.toString();
}

#30


数据优化一直是难题, 学习....

#31


引用 30 楼 ginger1024 的回复:
数据优化一直是难题, 学习....



学习中...

#1


优化数据库,在相关字段上建索引。或者采用分区表之类的。

hib一般也用的是数据库的分页,比如oracle的rownum等,单纯从sql上来说,很难优化了。
200w的数据量,通常查最后几页都需要差不多这个时间(存在order by)。

#2


引用 1 楼 crazylaa 的回复:
优化数据库,在相关字段上建索引。或者采用分区表之类的。

hib一般也用的是数据库的分页,比如oracle的rownum等,单纯从sql上来说,很难优化了。
200w的数据量,通常查最后几页都需要差不多这个时间(存在order by)。

优化数据库
感觉用hibernate做分页  很多小细节要注意的  

#3


优化数据库,在相关字段上建索引。或者采用分区表之类的。 

优化数据库,在相关字段上建索引
我没用过,不知道怎么操作,能否详细说一下?与存储过程相比呢?
我用的是SqlServer2005

#4


引用 3 楼 sw4433 的回复:
优化数据库,在相关字段上建索引。或者采用分区表之类的。

 优化数据库,在相关字段上建索引
 我没用过,不知道怎么操作,能否详细说一下?与存储过程相比呢?
 我用的是SqlServer2005


sqlserver不懂。

把hib生成的sql晒下?看看你有没有索引。。

#5


对了存储过程肯定也跟hib一样是用数据库的分页来做的了。如果sql一样的话,存储过程和hib调用,性能区别不会很大。

#6


Hibernate: select top 10 guestbook0_.id as id0_, guestbook0_.name as name0_, gue
stbook0_.email as email0_, guestbook0_.url as url0_, guestbook0_.title as title0
_, guestbook0_.context as context0_, guestbook0_.time as time0_ from guestBook.d
bo.guestBook guestbook0_ order by guestbook0_.id asc


#7


create index my_index on guestBook(id)

建立索引了速度好象还是一样慢!
是不是在数据库创建了索引就可以了?是否要象存储过程那样引用呢?

#8


关注中

#9


mark

#10


 order  by guestbook0_.id 
ID是主键的话,已经有索引了,你这里又没有where条件可作优化。。。
ID不是主键的话,看看ID上面有没有索引,没有的话,建一个。
create index idx_gbook_id on 表名(列名); --表名指数据库表名,列名指ID。这句话在数据库中做。
你这里没有where条件,一次全取200w排序。。。,从数据库来看,也没有办法分区优化了。。。。

楼主认命吧,或者加内存,加cpu。。。 hibernate已实现分页查询,数据量百万以上越往后的数据查询的越慢,怎么解决?

#11


id为主键,等于有索引了

速度还是很慢,Hinernate 难道只能就这样了?

#12


引用 11 楼 sw4433 的回复:
id为主键,等于有索引了

 速度还是很慢,Hinernate 难道只能就这样了?

没办法,我的机器1G内存,双核,也是只有PK的索引,oracle92数据库,200w数据,有order by,取最后10条也差不多这个时间(sql跟你的一样。。。)

#13


使用hibernate建议配上二级缓存,不然数据量大了,是非常耗性能的,而且你的延迟加载等等都得设置好,和主控,级联,不然极有可能把你的整个数据库给load出来
hibernate做的最好的就是缓存

#14


引用 13 楼 tianwailaifenglove 的回复:
使用hibernate建议配上二级缓存,不然数据量大了,是非常耗性能的,而且你的延迟加载等等都得设置好,和主控,级联,不然极有可能把你的整个数据库给load出来
 hibernate做的最好的就是缓存

哦?二级缓存什么意思?是不是比如我每页要查10条,但是它给我查一百条出来,然后每次翻页就从缓存里面拿啊?如果不是这样的话,难道200w也一次都放内存?
我不懂hib啊,纯粹瞎猜的,不用当真。

#15


引用楼主 sw4433 的回复:
hibernate已实现分页查询,查询前面的数据速度很快,但查询后面的数据就很慢:

比如我现在是200,0000条记录,
页面 是:首页 上一页 下一页 尾页

点首页或点下一页查询很快,但点尾页就要十几秒才能查询到,此时再点上一页也是需要十几秒才能查询到

也就是说越往后的数据查询的越慢,有什么好的办法能解决此问题?

有没有比较好的方法能显著提升速度?

可以从多方面下手:第一,可以为查询的设置索引;第二,优化查询,使用数据库分页(如Oracle的伪列);第三,用数据库存储过程来分页,返回一页的数据,也挺好。

#16


引用 13 楼 tianwailaifenglove 的回复:
使用hibernate建议配上二级缓存,不然数据量大了,是非常耗性能的,而且你的延迟加载等等都得设置好,和主控,级联,不然极有可能把你的整个数据库给load出来
hibernate做的最好的就是缓存


二级缓存 什么个意思?
怎么设置?

#17


也在研究这问题.关注此贴

#18


学习

#19


你项目真大。百w级数据。 

#20


   mark,关注 。。。

#21


jdbc 试试

#22


学习中..

#23


曾经看过一个人问SQL SERVER 2000如何去除伪分页 我才知道 HIBERNATE在SQL SERVER 2000里用的是伪分页  后来SQLSERVER 2005有类似Oracle的分页函数了之后 就可以通过修改数据库方言 让HIBERNATE支持真分页了

http://blog.csdn.net/tdl982324/archive/2008/07/03/2607674.aspx

LZ看这个

#24


引用 6 楼 sw4433 的回复:
Java codeHibernate: select top10 guestbook0_.id as id0_, guestbook0_.name as name0_, gue
stbook0_.email as email0_, guestbook0_.url as url0_, guestbook0_.title as title0
_, guestbook0_.context as context0_, guestbook0_.time as time0_ from guestBook.d
bo.guestBook guestbook0_ order by guestbook0_.id asc


这么写,where条件也没有,建了索引也用不到,每次运行都是从表的起始位置开始一行行扫描,当然越往后越慢了。

#25


	//查找记录
public List getAllGuestBooks(int firstResult,int maxResult){
Session session = this.getSession();
System.out.println("all");
List list = null;;
try {
Query query = session.createQuery("from GuestBook order by id asc"); 
query.setFirstResult(firstResult).setMaxResults(maxResult);
list = query.list();
} catch (HibernateException e) {
e.printStackTrace();
} finally{
session.close();
}
return list;
}

id为主键,我是传的是参数啊query.setFirstResult(firstResult).setMaxResults(maxResult);

#26


想用到id这个索引,sql语句要类似这样: select * from GuestBook where id = ?

select * from GuestBook这样是用不到的。

另外"from GuestBook order by id asc"这句得优化,把order by id asc去掉,id是主键,本身就是排好序的了

#27


引用 26 楼 sunnylyy 的回复:
想用到id这个索引,sql语句要类似这样: select * from GuestBook where id = ?

select * from GuestBook这样是用不到的。

另外"from GuestBook order by id asc"这句得优化,把order by id asc去掉,id是主键,本身就是排好序的了


sql语句我知道,如果是通过别的字段排序,怎么提高效率呢?比如通过name查询,by name desc
query.setFirstResult(firstResult).setMaxResults(maxResult); 
这是设置从哪条数据查,一次查询多少条数据

#28


跟一次查多少条关系不大,界面上强制加查询条件吧,然后用到索引。比如name字段建立索引,查询的时候类似这样:from GuestBook where name like 'AAA%'

order by尽量不要加了。

其实想想,对一个几百万的大表做分页显示,还不加任何查询条件,好象没什么必要。

#29


没有正式用过Hibernate..

但看过Hibernate的源码,,Hibernate 2针对于sqlserver 的分页只是逻辑分页。。

好像Hibernate 3也是逻辑分页。。。

只会在sql数据的时候在上top,只有第一页数据会出现的比较快,,而后翻页是查询出来的数据越来越多,再通过翻动游标返回数据。。。

像我正在用的ibatis也是如此,,,这些orm都唯独不支持sqlserver的物理分页。。

解决办法,,,楼主网上应该一大吧。。。基本上应该重载sqlserver的方言。。。

其实200w的数据也不算多,,,

贴点源码:
orcle:
public String getLimitString(String sql, boolean hasOffset) {
sql = sql.trim();
boolean isForUpdate = false;
if ( sql.toLowerCase().endsWith(" for update") ) {
sql = sql.substring( 0, sql.length()-11 );
isForUpdate = true;
}

StringBuffer pagingSelect = new StringBuffer( sql.length()+100 );
if (hasOffset) {
pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");
}
else {
pagingSelect.append("select * from ( ");
}
pagingSelect.append(sql);
if (hasOffset) {
pagingSelect.append(" ) row_ where rownum <= ?) where rownum_ > ?");
}
else {
pagingSelect.append(" ) where rownum <= ?");
}

if ( isForUpdate ) {
pagingSelect.append( " for update" );
}

return pagingSelect.toString();
}

sqlserver:

public String getLimitString(String querySelect, int offset, int limit) {
if ( offset > 0 ) {
throw new UnsupportedOperationException( "sql server has no offset" );
}
return new StringBuffer( querySelect.length()+8 )
.append(querySelect)
.insert( getAfterSelectInsertPoint(querySelect), " top " + limit )
.toString();
}

#30


数据优化一直是难题, 学习....

#31


引用 30 楼 ginger1024 的回复:
数据优化一直是难题, 学习....



学习中...