JQ Blog

Railsにおけるキャッシュの使い方

キャッシュ

  • キャッシュとは、使用頻度の高いデータを高速な記憶装置に蓄えておくことにより、いちいち低速な装置から読み出す無駄を省いて高速化すること。また、その際に使われる高速な記憶装置や、複製されたデータそのもののこと。

Railsにおけるキャッシュ

Rails3

  • ページキャッシュ(ページ全体をキャッシュ)
  • アクションキャッシュ(アクション単位でキャッシュ)
  • フラグメントキャッシュ(ページの一部をキャッシュ)

Rails4

Rails4ではページキャッシュとアクションキャシュは廃止され、フラグメントキャシュのみ使える。

フラグメントキャッシュとは

rails で利用できる view の一部分をキャッシュする機能。rails 3以上ならデフォルトで利用できる。railsは view のレンダリングが遅いので、アクセスの多いサイトはキャッシュの利用が必要になってくる。

書き方(Slim)

1
2
- cache {some_key} do
  = # cache したい HTML

キーにStringを指定した場合

下記のような場合に、

1
2
- cache "key" do
  = @some_db_data

この@some_db_dataの中身が変更されても、キャッシュには変更が反映されない。キャッシュのキーに含まれるdigestはあくまでHTMLを元に作られるため、データの変更があってもdigestは変更されないからである。
また、自動で付与されるdigestを利用しないようにするには

1
2
- cache "key", skip_digest: true do
  = @some_db_data

とする。この場合、HTMLに変更があったとしても、キャッシュには反映されず変更前のものが表示される。

キーを省略した場合

1
2
- cache do
  = @some_db_data

上記のように、キーを省略した場合は、ページのurlからキーが自動で作られる。url依存のキーなので、同じページでこの形を複数記述すると、どちらかのキャッシュが上書きされてめちゃくちゃになる。

キーにオブジェクトを指定した場合

1
2
- cache @object do
  = @object.text

オブジェクトを指定した場合は、@object.cache_keyがキャッシュのキーとなる。ActiveRecordのオブジェクトの場合、IDや、updated_atを元にキーが作成されるので、オブジェクトのupdated_atが変更されると自動でキャッシュも更新される。

1
2
3
- cache @objects do
  - @objects.each do |object|
    = object.text

上記のように配列にした場合は、各オブジェクトに対して cache_key が呼ばれてそれを連結したものがキャッシュのキーになる。よって配列の順番や中身が変更されればキャッシュは更新される。

Russian Doll Caching(ロシアンドールキャッシング)とは

ネストされたフラグメントキャッシュの内側のキャッシュが更新されると、外側のキャッシュも更新してくれる機能。rails 4ならデフォルトで利用可能。

1
2
3
4
5
6
7
8
- cache @company do
  h1
    = @company.name
  ul
    - cache @company.members
      - @company.members.each do |member|
        li
          = member.name

上記のようなネストされた構造のとき、membersに変更があったとしても、companyに変更がなければcompanyのキーが変更されず、キャッシュは更新されない。
しかし、memberのmodelに

1
2
3
class Member < ActiveRecord::Base
  belongs_to :company, touch: true
end

と書いておくと、ネストされた親のキーにも更新が伝搬してくれるようになる。

テスト

70個の親テーブルと1440個の子テーブルをViewに出すことでキャッシュのテストを実行してみたら、

  • キャッシュしていない場合
1
Completed 200 OK in 791ms (Views: 685.4ms | ActiveRecord: 93.5ms)
  • キャッシュした場合
1
Completed 200 OK in 31ms (Views: 28.8ms | ActiveRecord: 0.7ms)

圧倒的な結果が出てきた。

参照

RailsにおけるCacheの概念と使い方
rails 4 の fragment cache(フラグメントキャッシュ)まとめ