新手问题 will_paginate 分页过多 (大概 10000 页),点击最后几页的时候,速度明显变慢

suxiaohun · 2016年01月08日 · 最后由 suxiaohun 回复于 2016年01月14日 · 3603 次阅读

我用will_paginate分页, @questions = Question.paginate(page: params[:page], per_page: 15) db中数据大概在15w条左右,在点击最后几页的时候速度很慢,我从console中 得到sql在数据库中执行,确实就很慢。

我从网上查了查,说是offset过大,导致sql查询过慢,有什么好的方法解决这个问题吗? 看了一些优化,好像要写sql?

共收到 27 条回复

使用 id 来做分页,如

@questions = Question.where("questions.id > ?", 100).limit(15)

我从网上查了查,说是offset过大,导致sql查询过慢,有什么好的方法解决这个问题吗?

是的。 底层的话可以为表建合适的索引。还有一个最简单的方法,直接隐藏最后几页的button~很多网站都是这么做的,防止用户随意乱点

#1楼 @hz_qiuyuanxin id? 表中由于一些事务逻辑,id并不一定是连续的,如何根据page,per_page得到基数的这个id? 而且,我没把一些条件和排序贴出来,这样的话,id都是无序的

offset过大就是这种效果,不过每次只取一条结果的话,速度还不错,如果一页15个结果,可以分15次取出,你可以试一下,有没有效果不敢保证。

N 年前遇到过相同问题,因为数据不常变动,后来我做了冗余,多开一个text字段,然后从头到尾遍历一次,在新开的 text 字段存接下来的14个结果。跑一遍还是要一点时间的,但这之后只要查一条信息,就得到15条数据,多靠后都没关系。

如果更新一条数据,要把包含这条数据的所有相邻 text 字段都更新。这个过程慢一点没关系,不常更新。

不给查太大。

#6楼 @rei #2楼 @bright #4楼 @qinfanpeng

门户新闻可能不用查,但某些情况下,是必须查的。我的一个使用场景是40万数据,要查一条数据的前15条,后15条记录,我就用了冗余,更新和插入麻烦一点,实际效果还是相当好的。

#1楼 @hz_qiuyuanxin #2楼 @bright #5楼 @peter #6楼 @rei 谢谢各位的回答,我看看能不能说服需求 不显示最后几页,有点悬。 另外我测试优化的时候,遇到一个问题,速度非常快,但结果不一样

我本来打算先查id,然后inner join出来, select * from questions inner join (select id from questions limit 150000,15) as lim using(id); 后来发现是 只查id,并不是按照id自增顺序展示结果的,网上好像也没找到类似的情况, 不知道各位遇到过这种问题没? 如果加上 排序 select * from questions inner join (select id from questions ORDER BY id limit 150000,15) as lim using(id); 结果正常了,可惜速度又下去了 #5楼 @peter 只查一条试了一下,速度没有明显提高。

#2楼 @bright 没太听懂你的意思,是只取一部分数据吗?

#8楼 @suxiaohun 我的场景和你的不一样,我是 select * from table where keyword='foobar',然后在 foobar 这条记录里冗余其它15条结果。

你这种情况下,如果知道某页的第一个 id 是什么,那也可以用冗余的方法了。

#10楼 @peter 额 ,不好意思,我理解错了,你说的冗余我不是很明白,我这边的新数据更新的很频繁, 而且有两个字段内容特别多,应该不合适吧。

@rei 能给具体的实现细节说一下吗?"不给查太大" 是指每页的数吗?感觉效果一样啊

#12楼 @easonlovewan 页数大于某个值就直接返回空。

ruby-china的分页只能查看前69页,也是出于性能考虑吗?我一直在看老帖子啊。

#13楼 @rei 这样做确实可以,不过给用户的体验是不是不太好啊

#15楼 @easonlovewan 一般来说用户要的是搜索和过滤。

@postids = posts.paginate(:page => params[:page]).order('created_at DESC').select('id').to_a
@posts = Post.where('posts.id' => @postids).order('posts.created_at DESC').eager_load [:user]

专门针对MySQL傻叉的分页效率做优化。

#18楼 @msg7086 这样效果好吗?

#9楼 @easonlovewan 是的,比如只显示前十页

#19楼 @pathbox 至少比直接分页好多了。 MySQL就是这个问题很大,limit数据量一大就死。

#21楼 @msg7086 唉,还是限制个页数吧,剩下的给搜索

#22楼 @pathbox 嘛,随意。 反正我们系统里就是这个代码,5000页都是秒出的。

每次查询做limit,大于某个值,重新做查询。

@suxiaohun 分页条件,过大的offse 提供了一种解决方式,可以试一试

#26楼 @ibugs thanks ,我去试下

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册