Gem will_paginate 在数据多的时候 count (*) 很慢,有没有办法优化?

huacnlee · 2012年04月19日 · 最后由 huacnlee 回复于 2012年04月19日 · 4071 次阅读

will_paginate 由于需要取到总条数用于计算分页数,每次请求都会 count(*) 一下,这个在数据较多的情况下会很慢,而且这个 SQL 似乎是无法优化上去了。

不知道 will_paginate 有没有办法把 count 的 total_entries 给 cache 下来或直接指定一个数字用于计算分页,免去到 DB 里面 count 查询。

其实大多数时候无需显示完所有页的,只需要意思一下就好了。比如超过 100 也就不显示了。

貌似ActiveRecord的对象在调用size方法的时候都会再count(*)得到总数,直接to_a后再传进去如何? (以上回答未经仔细验证,不过to_a后再size的话就不会再进行 sql 查询了)

慢的情况其实是没有条件或条件出来的结果也是很多的情况,有很多条件的情况反而会快,因为条件过滤以后总个数少了(前提是有索引命中的情况)

这个没什么好办法。。cache 也许是个最实际的方式。

#3 楼 @bony 我刚才是了改造 paginate 方法,让它支持接受一个 total_entries 的参数,有传就直接省掉 count 动作,速度一下就提上去了。

@huacnlee 这肯定会快,但是感觉太死板了。超出这个 total 的范围以后的翻页怎么计算呢?

#5 楼 @bony 不管,像那种上 10 万数据的页面,分页显示那么多没必要的,谁会没事翻那些页啊,要看后面那些文章可以配合搜索和过滤用

counter cache 和计数表

优化方法很多啊 1.使用 MyISAM 表,count 很快的,因为是预先计算出来的。不过带 where 的 count 会慢。 2.使用 counter cache: 比如用户文章列表页面:把文章数量存在用户表里,分页的时候直接指定 total_entries => user.articles_count

3.计数表: 有些表是没有根的,像 user 表。可以直接创建一个计数用的表用来存储用户总数量,帖子数量,全局访问量等信息。同样是 counter cache 的思路。在分页的时候指定 total_entries => users_count

4.限制翻页数,比如淘宝的商品最多显示 100 页。

#8 楼 @hooopo will_paginate_mongoid 目前版本搞掉了 total_entries 参数,我自己 hack 了一下,搞定了。

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