我在 Rails 中做一個基于查詢的建議 API,建議在用戶輸入時回傳給用戶。為了避免過于頻繁地訪問資料庫,我決定快取記錄。
def cached_values
Rails.cache.fetch(:values_cached, expires_in: 1.day) do
Table.verified.select(:value).all
end
end
cached_values
=>
[#<Table:0x000056406fc70370 id: nil, value: "xxx">,
#<Table:0x000056406fc77f80 id: nil, value: "xxx">,
#<Table:0x000056406fc77d00 id: nil, value: "xxx">
...
我知道快取 ActiveRecord 條目不是一個好習慣,但是“已驗證”范圍相對較小(~6k 行),我想進一步查詢它。因此,當呼叫 API 時,我會查詢快取的值(簡化,真正的值已清理):
def query_cached(query)
cached_values.where("value LIKE '%#{query}%'").to_a
end
這里的問題是我已經測驗了快取和非快取查詢,后者具有更好的性能。設定Rails.logger.level = 0,我注意到快取的查詢仍然記錄資料庫查詢:
pry(main)> query_cached("a")
Table Load (1.2ms) SELECT "table"."value" FROM "table" WHERE "table"."verified" = TRUE AND (value LIKE '%a%')
我的猜測是,快取搜索既打開了與資料庫的連接,又加載了快取的記錄,這需要更多時間,但實際上是無用的。有沒有可靠的方法來檢查?如果快取只是較慢,也許仍然值得保留它并防止與資料庫的連接過多。
每個 10000 個查詢的基準:
user system total real
uncached 20.110681 0.369983 20.480664 ( 26.935934)
cached 23.750934 0.753414 24.504348 ( 34.198694)
uj5u.com熱心網友回復:
需要注意的是,all它不會回傳陣列中的所有記錄。相反,它回傳一個ActiveRecord::Relation物件。這種關系表示一個資料庫查詢,該查詢可能稍后被呼叫,或者可以通過更多條件進行擴展,例如.where("value LIKE '%#{query}%'"). 如果all已經回傳了一個記錄陣列,那么您將無法向其中添加附加條件,.where("value LIKE '%#{query}%'")因為where陣列上不存在。
因為您只快取了表示資料庫查詢的關系,該查詢可以通過呼叫需要實際記錄但尚未運行的方法來運行(如each, to_a, first),因此在這種情況下快取是無用的。
此外,我認為快取在此示例的背景關系中根本沒有用,因為您需要為每個不同的用戶輸入快取不同的值。這意味著如果用戶搜索,foo那么您可以快取該結果,但如果另一個用戶搜索bar您,則仍然需要對資料庫運行另一個查詢。只有當兩個用戶搜索相同的字串時,快取才有用。
在您的示例中,資料庫中的全文索引可能是更好的選擇。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/408609.html
標籤:
