動かざることバグの如し

近づきたいよ 君の理想に

巨大レコードのkaminariページネーションは工夫が必要

railsネタです

kaminariが重い

kaminariとは言わずと知れたRubyのページネーションライブラリ。Railsとの親和性が非常に高く、ソースコードをちょちょっと弄るだけで難しいページネーションが作れる。

が、ページネーション対象のデータの件数が多いと(10万件超えとか)、表示にすごく時間がかかるようになってしまう。

   (171006.2ms)  SELECT COUNT(*) FROM `posts`
  Rendered posts/index.html.erb within layouts/application (172073.0ms)
Completed 200 OK in 172318ms (Views: 172092.3ms | ActiveRecord: 171666.5ms)

え。。。

原因

重い原因はcount(*) そもそもページネーションするのに全体の件数が必要なので、kiminariは自動でselect count(*)を毎回実行せざる得ない。

が、巨大レコードになるとselect count(*)が辛くなる。。よって重くなるのである。

対策

比較的最近だが、それ専用のオプションができた。without_countをつけてあげる。

例えば以下の例だと、

@posts = Post.order("datetime desc").page(params[:page]).per(20)

こんな感じ

@posts = Post.order("datetime desc").page(params[:page]).without_count.per(20)

するとkaminariはselect count(*)をしなくなる。

が、それだと当然今までのページネーションもできなくなるので、

<%= paginate(@posts) %>

<%= link_to_prev_page @posts, '前のページ' %>
<%= link_to_next_page @posts, '次のページ' %>

等に書き換える必要がある。