25

私のサイトのDB負荷は非常に高くなっているので、結果が変わらない1時間に数千回呼び出される一般的なクエリをキャッシュするときが来ました。たとえば、私の都市モデルでは、次のようにします。

def self.fetch(id)   
  Rails.cache.fetch("city_#{id}") { City.find(id) }   
end 

def after_save
  Rails.cache.delete("city_#{self.id}")
end

def after_destroy
  Rails.cache.delete("city_#{self.id}")
end

したがって、City.find(1)を初めてDBにヒットしたときに、次の1000回は、メモリから結果を取得できるようになりました。素晴らしい。しかし、cityへの呼び出しのほとんどはCity.find(1)ではなく@ user.city.nameであり、Railsはフェッチを使用せずにDBに再度クエリを実行します...これは理にかなっていますが、私が望んでいることとは異なります。

City.find(@ user.city_id)を実行できますが、それは醜いです。

皆さんへの私の質問です。賢い人は何をしていますか?これを行う正しい方法は何ですか?

4

4 に答える 4

23

キャッシングに関して、いくつかのマイナーなポイント:

オブジェクトのタイプとIDを区切るにはスラッシュを使用する価値があります。これは、Railsの規則です。さらに良いことに、ActiveRecordモデルは、テーブル名とID、「cities/13」などの一意の識別子を提供するcacke_keyインスタンスメソッドを提供します。

after_saveフィルターのマイナーな修正。データは手元にあるので、削除するのではなく、キャッシュに書き戻すことをお勧めします。これにより、データベースへの1回の移動を節約できます;)

def after_save
  Rails.cache.write(cache_key、self)
終わり

質問の根本については、@ user.city.nameを継続的にプルしている場合、2つの実際の選択肢があります。

  • ユーザーの都市名をユーザー行に非正規化します。@ user.city_name(city_id外部キーを保持します)。この値は、保存時に書き込む必要があります。

-また-

  • User.fetchメソッドを実装して、都市を熱心にロードします。これは、都市の行の内容(名前など)が変更されない場合にのみ実行してください。変更しないと、キャッシュの無効化に関してワームの缶を開く可能性があります。

個人的な意見:基本的なIDベースのフェッチメソッドを実装して(またはプラグインを使用して)memcachedと統合し、都市名をユーザーの行に非正規化します。

私は個人的にキャッシュされたモデルスタイルのプラグインの大ファンではありません。急いで成長していない開発時間を大幅に節約したプラグインを見たことがありません。

データベースクエリが多すぎる場合は、まだ行っていない場合は、(:includeを介して)積極的な読み込みを確認する価値があります。これは、データベースクエリの量を減らすための最初のステップです。

于 2008-12-06T05:22:48.230 に答える
0

Rails 2.2 に含まれているMemoizationを見てみましょう。

「メモ化とは、メソッドを一度初期化してから、繰り返し使用するためにその値を隠しておくパターンです。」

最近、 Railscastのすばらしいエピソードがありました。

Railscast の簡単なコード サンプル:

class Product < ActiveRecord::Base
  extend ActiveSupport::Memoizable

  belongs_to :category

  def filesize(num = 1)
    # some expensive operation
    sleep 2
    12345789 * num
  end
  memoize :filesize
end

メモ化の詳細

于 2008-12-05T19:24:52.133 に答える
-1

cached_modelを確認する

于 2008-12-05T19:20:03.437 に答える