6

Von dem was ich von russischen Puppe Caching in Rails verstehe, wäre es schädlich für lastbezogene Objekte oder Objektlisten, wenn wir RDC (Russian Doll Caching) tun, weil wir in RDC nur laden Top-Level-Objekt aus der Datenbank, und suchen Sie seine zwischengespeicherte gerenderte Vorlage und dienen. Wenn wir eifrig verwandte Objektlisten laden würden, wäre das nutzlos, wenn der Cache nicht abgestanden wäre.Rails Russian Doll Caching und N + 1

Ist mein Verständnis korrekt? Wenn ja, wie stellen wir sicher, dass wir alle verwandten Objekte beim allerersten Aufruf laden, um die Kosten von N + 1 Abfragen während der ersten Ladung (wenn der Cache nicht warm ist) nicht zu bezahlen.

Antwort

4

Korrekt - wenn eine Sammlung oder ein kompliziertes Objekt mit vielen Assoziationen geladen wird, kann ein kostspieliger Aufruf zum eifrigen Laden aller Objekte und Verknüpfungen durch einen schnellen, einfachen Aufruf vermieden werden. Die rails guide for caching hat ein gutes Beispiel, aber es ist ein bisschen aufgeteilt. Mit Blick auf dem gemeinsamen Anwendungsfall eine Sammlung Cachen (dh der Index Aktion in Rails):

<% 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 %> 

Dieses (verkürzt) Beispiel tut 1 einfacher DB-Aufruf Product.maximum(:updated_at)Product.all machte einen viel teurer Anruf zu vermeiden.

Für einen kalten Cache (die zweite Frage) ist es wichtig, N + 1 durch eifriges Laden assoziierter Objekte zu vermeiden. Wir wissen jedoch, dass wir diesen teuren Anruf tätigen müssen, da der erste Cache-Lesevorgang für die Sammlung fehlgeschlagen ist. In Rails erfolgt dies normalerweise mit includes. Wenn ein Product zu viele Order s gehört, dann so etwas wie:

<% 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 %> 

Im kalten Cache Fall noch wir einen Cache für die Sammlung und jedes Mitglied lesen tun, aber in der teilweise warmen Cache Fall werden wir Rendering überspringen für einen Teil der Mitglieder. Beachten Sie, dass diese Strategie auf einer s Assoziationen basiert, die korrekt auf touch eingerichtet wird, wenn verknüpfte Objekte aktualisiert werden.

Update: This blog post beschreibt ein komplexeres Muster zur weiteren Optimierung der Gebäudemeldungen für teilweise zwischengespeicherte Sammlungen. Anstatt die gesamte Sammlung neu zu erstellen, ruft sie massenhaft alle verfügbaren zwischengespeicherten Werte ab, führt dann eine Massenabfrage nach den verbleibenden Werten durch (und aktualisiert den Cache). Dies ist auf verschiedene Arten hilfreich: Das Lesen des Massencaches ist schneller als das Lesen von N + 1-Caches, und die Massenabfrage an die Datenbank zum Erstellen des Caches ist ebenfalls kleiner.