
問題描述
在Ruby on Rails對接redis時候,我的代碼如下:
category_list = Rails.cache.fetch("category_all", expires_in: 12.hours) do
Category.all
end
renderFindResponse category_list, {
totalCount: category_list.size,
}
end
結(jié)果發(fā)現(xiàn)即使生成了redis緩存文件,但是每次請求仍然會繼續(xù)請求數(shù)據(jù)庫而不是優(yōu)先拿緩存,這是為什么呢?
根本原因
經(jīng)過排查發(fā)現(xiàn),緩存內(nèi)容出現(xiàn)了問題。解釋如下:
-
Category.all
Category.all返回的是一個ActiveRecord::Relation對象。這種對象本質(zhì)上是數(shù)據(jù)庫查詢的一個待執(zhí)行的封裝,它并沒有立即執(zhí)行查詢。只有在需要讀取數(shù)據(jù)時(比如對數(shù)據(jù)進行遍歷、計數(shù)或轉(zhuǎn)換時),ActiveRecord::Relation對象才會實際觸發(fā)數(shù)據(jù)庫查詢。
當嘗試緩存Category.all時,實際上緩存的是這個ActiveRecord::Relation對象,而不是查詢結(jié)果。當從緩存中取出對象并嘗試對其進行操作時(例如迭代結(jié)果),才會觸發(fā)數(shù)據(jù)庫查詢。這意味著每次訪問緩存并使用結(jié)果時,仍可能會執(zhí)行數(shù)據(jù)庫查詢。
-
Category.all.to_a
Category.all.to_a會強制執(zhí)行數(shù)據(jù)庫查詢,并將結(jié)果立即加載為一個數(shù)組。to_a會觸發(fā)ActiveRecord::Relation對象執(zhí)行SQL查詢,并返回包含所有記錄的數(shù)組。當這個數(shù)組被緩存后,訪問緩存并使用這些數(shù)據(jù)時,不會再觸發(fā)數(shù)據(jù)庫查詢,因為你正在操作的是已經(jīng)加載到內(nèi)存中的數(shù)據(jù)元素。
緩存Category.all.to_a實際上緩存的是一次具體的數(shù)據(jù)庫查詢結(jié)果。這對減少數(shù)據(jù)庫訪問非常有效,因為一旦數(shù)據(jù)被緩存,所有對這些數(shù)據(jù)的后續(xù)訪問都將直接從緩存讀取數(shù)據(jù),而不需要再次查詢數(shù)據(jù)庫。
結(jié)論:為什么選擇Category.all.to_a進行緩存
減少數(shù)據(jù)庫負載:緩存查詢結(jié)果(已經(jīng)加載的數(shù)據(jù))可以顯著減少對數(shù)據(jù)庫的請求,尤其是在數(shù)據(jù)不經(jīng)常變化的情況下。這有助于提高應(yīng)用性能,尤其是在處理大量數(shù)據(jù)時。
改善應(yīng)用性能:通過緩存預(yù)先加載的數(shù)據(jù)數(shù)組,可以實現(xiàn)更快的數(shù)據(jù)訪問速度,因為從緩存讀取數(shù)據(jù)一般要比執(zhí)行數(shù)據(jù)庫查詢來得快。
總結(jié),盡管Category.all和Category.all.to_a在某些上下文中可能產(chǎn)生相似的結(jié)果,但在緩存策略中選擇使用to_a確保了實際的查詢結(jié)果被緩存,而不是查詢本身,這有助于優(yōu)化Rails應(yīng)用的性能。
THE END!