查询 Rails 中的缓存记录似乎很慢

Querying cached records in Rails seems slow

我正在 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)

重要的是要注意 all 并不 return 数组中的所有记录。相反,它 return 是一个 ActiveRecord::Relation 对象。这样的关系代表一个数据库查询,以后可能会被调用,或者可以通过更多条件扩展,例如 .where("value LIKE '%#{query}%'")。如果 all 已经 return 编辑了一个记录数组,那么您将无法使用 .where("value LIKE '%#{query}%'") 添加附加条件,因为数组中不存在 where

因为您仅通过调用需要实际记录的方法(如 eachto_a、[=18] 来缓存表示可以 运行 的数据库查询的关系=]) 但还没有 运行,在这种情况下缓存是无用的。

此外,我认为缓存在此示例的上下文中根本没有用,因为您需要为每个不同的用户输入缓存不同的值。这意味着如果用户搜索 foo 那么您可以缓存该结果,但是如果另一个用户随后搜索 bar 您仍然需要 运行 对数据库的另一个查询。只有当两个用户搜索 相同的 字符串时,缓存才可能有用。

在您的示例中,数据库中的全文索引可能是更好的选择。