從我所瞭解的俄羅斯娃娃緩存在Rails中,當我們正在執行RDC(俄羅斯娃娃緩存)時,對負載相關的對象或對象列表是不利的,因爲在RDC中,來自數據庫的頂級對象,並查找其緩存的呈現模板並提供服務。如果我們急於加載相關的對象列表,如果緩存沒有陳舊,這些對象列表將無用。Rails俄羅斯娃娃緩存和N + 1
我的理解是否正確?如果是的話,我們如何確保在第一次調用時我們急切地加載所有相關對象,以便在第一次加載時(緩存不暖時)不支付N + 1查詢的開銷。
從我所瞭解的俄羅斯娃娃緩存在Rails中,當我們正在執行RDC(俄羅斯娃娃緩存)時,對負載相關的對象或對象列表是不利的,因爲在RDC中,來自數據庫的頂級對象,並查找其緩存的呈現模板並提供服務。如果我們急於加載相關的對象列表,如果緩存沒有陳舊,這些對象列表將無用。Rails俄羅斯娃娃緩存和N + 1
我的理解是否正確?如果是的話,我們如何確保在第一次調用時我們急切地加載所有相關對象,以便在第一次加載時(緩存不暖時)不支付N + 1查詢的開銷。
正確 - 在加載具有多個關聯的集合或複雜對象時,通過執行快速,簡單的調用可以避免昂貴的調用以加載所有對象和關聯。
rails guide for caching確實有一個很好的例子,但是,它分裂了一點。縱觀緩存集合(即在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 %>
這(濃縮)例如做1簡單DB調用Product.maximum(:updated_at)
避免做一個更昂貴的調用Product.all
。
對於冷藏緩存(第二個問題),通過急切加載關聯對象來避免N + 1是很重要的。但是,我們知道我們需要做這個昂貴的調用,因爲爲集合讀取的第一個緩存未命中。在Rails中,這通常使用includes
來完成。如果Product
屬於多個Order
s,則是這樣的:
<% 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
s關聯正確設置爲touch
。
更新:This blog post描述了一個更復雜的模式,以進一步優化部分緩存集合的建築響應。它不是重建整個集合,而是批量獲取所有可用的緩存值,然後對其餘值進行批量查詢(並更新緩存)。這在幾個方面是有幫助的:批量高速緩存讀取速度比N + 1高速緩存讀取速度快,並且對數據庫構建高速緩存的批量查詢也更小。