6

從我所瞭解的俄羅斯娃娃緩存在Rails中,當我們正在執行RDC(俄羅斯娃娃緩存)時,對負載相關的對象或對象列表是不利的,因爲在RDC中,來自數據庫的頂級對象,並查找其緩存的呈現模板並提供服務。如果我們急於加載相關的對象列表,如果緩存沒有陳舊,這些對象列表將無用。Rails俄羅斯娃娃緩存和N + 1

我的理解是否正確?如果是的話,我們如何確保在第一次調用時我們急切地加載所有相關對象,以便在第一次加載時(緩存不暖時)不支付N + 1查詢的開銷。

回答

4

正確 - 在加載具有多個關聯的集合或複雜對象時,通過執行快速,簡單的調用可以避免昂貴的調用以加載所有對象和關聯。

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高速緩存讀取速度快,並且對數據庫構建高速緩存的批量查詢也更小。