6

Railsでのロシア人形のキャッシュについて私が理解していることから、RDC(ロシア人形のキャッシュ)を実行しているときに、関連するオブジェクトまたはオブジェクトリストを熱心にロードすることは有害です.RDCではデータベースからトップレベルのオブジェクトをロードし、そのキャッシュされたレンダリングされたテンプレートとサーブ。キャッシュが古くない場合、関連するオブジェクト リストを熱心にロードすると、役に立たなくなります。

私の理解は正しいですか?はいの場合、最初の呼び出しですべての関連オブジェクトを熱心にロードして、最初のロード中に N+1 クエリのコストを支払わないようにするにはどうすればよいですか (キャッシュがウォームでない場合)。

4

1 に答える 1

4

正解 - 多くの関連付けを持つコレクションまたは複雑なオブジェクトをロードする場合、高速で単純な呼び出しを行うことで、すべてのオブジェクトと関連付けを熱心にロードするためのコストのかかる呼び出しを回避できます。

キャッシングのRails ガイドには良い例がありますが、少し分割されています。コレクションをキャッシュする一般的な使用例 (つまり、Rails の index アクション) を見ると、次のようになります。

<% cache("products/all-#{Product.maximum(:updated_at).try(:to_i)}") do %>
  All available products:
  <% Product.all.each do |p| %>
    <% cache(p) do %>
      <%= link_to p.name, product_url(p) %>
    <% end %>
  <% end %>
<% end %>

この (要約された) 例では、単純な DB 呼び出しを 1 回Product.maximum(:updated_at)実行して、はるかにコストのかかる呼び出しを回避していますProduct.all

コールド キャッシュ (2 番目の質問) の場合、関連付けられたオブジェクトを熱心に読み込み、N+1 を回避することが重要です。ただし、コレクションの最初のキャッシュ読み取りが失敗したため、この高価な呼び出しを行う必要があることはわかっています。Rails では、これは通常、 を使用して行われincludesます。a が複数の s にProduct属している場合、Order次のようになります。

<% cache("products/all-#{Product.maximum(:updated_at).try(:to_i)}") do %>
  All available products:
  <% Product.includes(:orders).all.each do |p| %>
    <% cache(p) do %>
      <%= link_to p.name, product_url(p) %>
      Bought at:
      <ul>
        <% p.orders.each do |o| %>
          <li><%= o.created_at.to_s %></li>
        <% end %>
      </ul>
    <% end %>
  <% end %>
<% end %>

コールド キャッシュの場合でも、コレクションと各メンバーのキャッシュ読み取りを行いますが、部分的なウォーム キャッシュの場合は、メンバーの一部のレンダリングをスキップします。この戦略は、関連付けられたオブジェクトが更新さProductれるまで関連付けが正しく設定されていることに依存していることに注意してください。touch

更新:このブログ投稿では、部分的にキャッシュされたコレクションのビルド応答をさらに最適化するためのより複雑なパターンについて説明しています。コレクション全体を再構築する代わりに、使用可能なすべてのキャッシュされた値を一括フェッチしてから、残りの値に対して一括クエリを実行します (そしてキャッシュを更新します)。これは、いくつかの点で役立ちます。一括キャッシュ読み取りは N+1 キャッシュ読み取りより高速であり、キャッシュを構築するための DB への一括クエリも小さくなります。

于 2015-02-28T21:38:06.930 に答える