will_paginate 由于需要取到总条数用于计算分页数,每次请求都会 count(*) 一下,这个在数据较多的情况下会很慢,而且这个 SQL 似乎是无法优化上去了。
不知道 will_paginate 有没有办法把 count 的 total_entries 给 cache 下来或直接指定一个数字用于计算分页,免去到 DB 里面 count 查询。
其实大多数时候无需显示完所有页的,只需要意思一下就好了。比如超过 100 也就不显示了。
貌似ActiveRecord的对象在调用size方法的时候都会再count(*)得到总数,直接to_a后再传进去如何? (以上回答未经仔细验证,不过to_a后再size的话就不会再进行 sql 查询了)
ActiveRecord
size
count(*)
to_a
慢的情况其实是没有条件或条件出来的结果也是很多的情况,有很多条件的情况反而会快,因为条件过滤以后总个数少了(前提是有索引命中的情况)
这个没什么好办法。。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 了一下,搞定了。