11

私のバージョンは次のとおりです。

  • レール: 3.2.6
  • ダリ: 2.1.0

私の環境は次のとおりです。

  • config.action_controller.perform_caching = true
  • config.cache_store = :dalli_store, 'localhost:11211', {:namespace => 'MyNameSpace'}

私が書くとき:

 Rails.cache.fetch(key) do
     User.where('status = 1').limit(1000)
 end

ユーザー モデルをキャッシュできません。私が使用する場合

 Rails.cache.fetch(key) do
     User.all
 end

キャッシュできます。クエリ結果をキャッシュする方法は?

4

4 に答える 4

38

理由は

User.where('status = 1').limit(1000)

ActiveRecord::Relation実際にはクエリではなくスコープである を返します。Rails はスコープをキャッシュします。

クエリをキャッシュする場合は、最後に などのクエリ メソッドを使用する必要があります#all

Rails.cache.fetch(key) do
  User.where('status = 1').limit(1000).all
end

ActiveRecord オブジェクトをキャッシュすることは決して良い考えではないことに注意してください。オブジェクトをキャッシュすると、状態と値が矛盾する場合があります。該当する場合は、常にプリミティブ オブジェクトをキャッシュする必要があります。この場合、ID をキャッシュすることを検討してください。

ids = Rails.cache.fetch(key) do
  User.where('status = 1').limit(1000).pluck(:id)
end
User.find(ids)

この場合、User.findそれへの呼び出しは常に実行されると主張するかもしれません。確かにそうですが、主キーを使用したクエリは高速で、前述の問題を回避できます。さらに、アクティブなレコード オブジェクトのキャッシュはコストがかかる可能性があり、たった 1 つのキャッシュ エントリですべての Memcached メモリがすぐにいっぱいになってしまう可能性があります。ID をキャッシュすることで、この問題も回避できます。

于 2012-06-27T07:21:11.923 に答える
3

選択した回答に加えて、Rails 4+ の場合、スコープの結果を取得するload代わりに使用する必要があります。all

于 2015-02-16T15:54:32.333 に答える
3

Rails.cache.fetchブロックが評価したものを正確にキャッシュします。

 User.where('status = 1').limit(1000)

は単なるスコープなので、キャッシュされるのは ActiveRecord::Relation オブジェクト、つまりクエリであり、その結果ではありません (クエリがまだ実行されていないため)。

便利なものをキャッシュしたい場合は、ブロック内でクエリを強制的に実行する必要があります。

User.where('status = 1').limit(1000).all

Rails 4 ではall、リレーションのロードを強制しないことに注意してください -to_a代わりに使用してください

于 2012-06-27T07:14:31.897 に答える
0

使用する

User.where("status = 1").limit(1000).all

動作するはずです。

于 2012-06-27T06:51:15.470 に答える