#フラグメントキャッシュ
##はじめに
昨日からずっとMysqlを導入しようと頑張りましたが、エラーが消えません....今日は諦めてキャッシュを調べます。
##キャッシュって?
キャッシュとはリクエストして生成されたコンテンツを保存しておき、次回同じようなリクエストが発生したときのレスポンスでそのコンテンツを再利用することです。つまりアプリケーションのパフォーマンスが上がります。
キャッシュにも色々種類があり、今回はフラグメントキャッシュについてです。
##フラグメントキャッシュ
WEBアプリケーションにおいて、ページ内には色々な要素があります。それら一つ一つにキャッシュの設定をする場合はこのフラグメントキャッシュを用います。こやつはリクエストがあると一意のキーを備えたキャッシュを保存する。そして次回以降はこのキーを元にキャッシュを参照し読み込む。
またレコードなどが更新された場合、古い情報であるキャッシュを読み込まれると困るので、更新時にこのキーも更新される仕組み。
##実装
大胆なテストでユーザー999人読み込むページを作った。
- @user_index.each do |user|
- cache user do
= user.name
%br
上記のcache
で囲む部分でキャッシュを保存してくれる。今回はuserオブジェクトを指定した場合、updated_at値が更新されると新しいキーが生成され、そのキーで新しいキャッシュを保存します。故に古いキャッシュはレコード更新時に使えなくなります。
またviewを更新した時も古いキャッシュは使えなくなります。
##ログをみてみる。
最初のアクセスだと下記のログのとおり、キャッシュを生成しています。読み込みは805msかかってます。
Started GET "/users/" for 127.0.0.1 at 2018-12-21 22:52:31 +0900
(0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
Processing by UsersController#index as HTML
Rendering users/index.html.haml within layouts/application
User Load (6.1ms) SELECT "users".* FROM "users"
Read fragment views/users/1-20181221130709434304/6767027a5e612f0792a66689fb4b447b (0.2ms)
Write fragment views/users/1-20181221130709434304/6767027a5e612f0792a66689fb4b447b (0.1ms)
Read fragment views/users/2-20181221130709437544/6767027a5e612f0792a66689fb4b447b (0.1ms)
Write fragment views/users/2-20181221130709437544/6767027a5e612f0792a66689fb4b447b (0.0ms)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~略~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Read fragment views/users/998-20181221130711798706/6767027a5e612f0792a66689fb4b447b (0.0ms)
Write fragment views/users/998-20181221130711798706/6767027a5e612f0792a66689fb4b447b (0.0ms)
Read fragment views/users/999-20181221130711800729/6767027a5e612f0792a66689fb4b447b (0.0ms)
Write fragment views/users/999-20181221130711800729/6767027a5e612f0792a66689fb4b447b (0.1ms)
Rendered users/index.html.haml within layouts/application (581.9ms)
Completed 200 OK in 805ms (Views: 786.7ms | ActiveRecord: 6.7ms)
2回目のアクセスは下記のとおりキャッシュを読み込んでいるのがわかります。時間も368msと半分になっています。
Read fragment views/users/992-20181221130711783094/6767027a5e612f0792a66689fb4b447b (0.0ms)
Read fragment views/users/993-20181221130711785249/6767027a5e612f0792a66689fb4b447b (0.0ms)
Read fragment views/users/994-20181221130711787733/6767027a5e612f0792a66689fb4b447b (0.0ms)
Read fragment views/users/995-20181221130711791279/6767027a5e612f0792a66689fb4b447b (0.0ms)
Read fragment views/users/996-20181221130711793623/6767027a5e612f0792a66689fb4b447b (0.0ms)
Read fragment views/users/997-20181221130711796211/6767027a5e612f0792a66689fb4b447b (0.0ms)
Read fragment views/users/998-20181221130711798706/6767027a5e612f0792a66689fb4b447b (0.1ms)
Read fragment views/users/999-20181221130711800729/6767027a5e612f0792a66689fb4b447b (0.0ms)
Rendered users/index.html.haml within layouts/application (349.1ms)
Completed 200 OK in 368ms (Views: 360.5ms | ActiveRecord: 4.7ms)
次にviewを更新したらどうなるか、試しに出力するユーザー数を一人にしました。
- cache @user_index do
= @user_index.name
アクセスすると前のキャッシュが使われず、新しくキャッシュを作ってくれています。
Started GET "/users/" for 127.0.0.1 at 2018-12-21 23:08:20 +0900
Processing by UsersController#index as HTML
User Load (0.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
Rendering users/index.html.haml within layouts/application
Read fragment views/users/1-20181221130709434304/1c0a43827bf36fbe2c51c42f1cf3c2ec (0.0ms)
Write fragment views/users/1-20181221130709434304/1c0a43827bf36fbe2c51c42f1cf3c2ec (0.0ms)
Rendered users/index.html.haml within layouts/application (4.2ms)
Completed 200 OK in 30ms (Views: 23.6ms | ActiveRecord: 0.3ms)
ではレコードを更新してみましょう。からまた確認してみましょう。
Started PATCH "/users/1" for 127.0.0.1 at 2018-12-21 23:15:38 +0900
Processing by UsersController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"n2Uhv5YijVEVXboMTpX5O6eKPwETEQoXWK7qLiPCNHx2gPt9AyD8BIcWHihtdkQasiTTxebPPwjbWnZGAeFZzw==", "user"=>{"name"=>"tanaka"}, "commit"=>"送信", "id"=>"1"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE (1) LIMIT ? [["LIMIT", 1]]
(0.1ms) begin transaction
SQL (0.6ms) UPDATE "users" SET "name" = ?, "updated_at" = ? WHERE "users"."id" = ? [["name", "tanaka"], ["updated_at", "2018-12-21 14:15:38.941375"], ["id", 1]]
(1.4ms) commit transaction
~略~
Started GET "/users/" for 127.0.0.1 at 2018-12-21 23:15:48 +0900
Processing by UsersController#index as HTML
User Load (0.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
Rendering users/index.html.haml within layouts/application
Read fragment views/users/1-20181221141538941375/1c0a43827bf36fbe2c51c42f1cf3c2ec (0.1ms)
Write fragment views/users/1-20181221141538941375/1c0a43827bf36fbe2c51c42f1cf3c2ec (0.1ms)
Rendered users/index.html.haml within layouts/application (5.1ms)
Completed 200 OK in 31ms (Views: 25.5ms | ActiveRecord: 0.3ms)
また新しくキャッシュが更新されてますね!これで古い情報は表示されません。
##まとめ
MySQLのせいで時間が......
ですが基本的なフラグメントキャッシュはわかりましたね。気がかりなのは今回時間が無かったので大胆な例しか思いつかず、999人のユーザーを表示するようにしましたが、そのせいかキャッシュを使ってもロード時間は半分にしかなりませんでした。参考記事とかだともっと早くなってたのですがね...キャッシュを使えばいい!って考えはダメなのでしょうね。
当たり前でしょうけど。とりあえずキャッシュの流れが見れてよかったです。
MySQLは許さない。
##参考にしたの
Railsのフラグメントキャッシュについて調べてみた
https://qiita.com/suketa/items/eeae7e2196520323f694
Rails のキャッシュ: 概要
https://railsguides.jp/caching_with_rails.html#%E3%83%95%E3%83%A9%E3%82%B0%E3%83%A1%E3%83%B3%E3%83%88%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5