2012-06-27 9 views
10

Moja wersja jest:Zamieszanie buforowanie aktywne zapytania rekord z Rails.cache.fetch

  • Rails 3.2.6
  • dalli: 2.1.0

Moja ENV wynosi:

  • config.action_controller.perform_caching = true
  • config.cache_store =: dalli_store, 'loc alhost: 11211' , {: namespace => 'MyNamespace'}

Kiedy piszę:

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

Model użytkownik może nie być buforowane. Jeśli używam tego obiektu, można go zapisać w pamięci podręcznej. Jak buforować wynik zapytania?

Odpowiedz

30

powodem jest fakt

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

zwraca ActiveRecord::Relation która jest faktycznie jak poradzić sobie, a nie zapytanie. Railsy buforują zakres.

Jeśli chcesz buforować zapytanie, musisz użyć metody zapytania na końcu, na przykład #all.

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

Uwaga nigdy nie jest dobry pomysł, aby buforować ActiveRecord obiekty. Buforowanie obiektu może spowodować niespójne stany i wartości. Zawsze należy buforować obiekty pierwotne, jeśli dotyczy. W takim przypadku rozważ buforowanie identyfikatorów.

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

Można argumentować, że w tym przypadku wywołanie User.find to zawsze wykonywany. To prawda, ale zapytanie za pomocą klucza głównego jest szybkie i omija problem, który opisałem wcześniej.Co więcej, buforowanie aktywnych obiektów rekordów może być kosztowne i szybko może skończyć się wypełnianie wszystkich pamięci Memcached za pomocą jednego pojedynczego wpisu pamięci podręcznej. Identyfikatory buforowania również zapobiegną temu problemowi.

+0

thx. Jeśli mam model kategorii, może mieć mniej niż 100 rekordów, cache Category.all jest dobrym pomysłem? nie buforuje identyfikatora cateogry – tinylian

+0

Czy najpierw zmienię Category.all na json i cache je w memcached? – tinylian

+1

To bardzo ważny i subtelny problem; Właśnie zdaliśmy sobie sprawę, że ten problem wkradł się do naszej aplikacji - różnica między 'Foo.where (bar: 'fubar')' i 'Foo.where (bar: 'fubar'). Wszystko" jest zupełnie inne niż/t caching, i coś, co może łatwo i subtelnie wślizgnąć się do twojej bazy kodów. Sprawdzaj i regularnie sprawdzaj, jeśli korzystasz z buforowania. –

0

Korzystanie

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

powinno działać.

2

Rails.cache.fetch buforuje dokładnie to, co blok ocenia.

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

jest tylko zakres, więc co zostaje w pamięci podręcznej jest właśnie przedmiotem ActiveRecord :: Relacja, czyli zapytania, ale nie jego wyniki (bo kwerenda nie została jeszcze wykonana).

Jeśli chcesz coś pożytecznego być buforowane, trzeba wymusić wykonanie kwerendy wewnątrz bloku, na przykład wykonując

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

Zauważ, że na szynach 4, all nie zmusza załadunku relacja - użyj to_a zamiast

3

Oprócz wybranej odpowiedzi: w przypadku Railsów 4+ zamiast all należy użyć wyniku, aby uzyskać wynik zakresu.

+0

'User.find (1) .load' daje mi' ArgumentError: niepoprawna liczba argumentów (przy 0, oczekiwane 1..2) 'na Railsach 4.1.15 – Kelseydh