查询 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
。
因为您仅通过调用需要实际记录的方法(如 each
、to_a
、[=18] 来缓存表示可以 运行 的数据库查询的关系=]) 但还没有 运行,在这种情况下缓存是无用的。
此外,我认为缓存在此示例的上下文中根本没有用,因为您需要为每个不同的用户输入缓存不同的值。这意味着如果用户搜索 foo
那么您可以缓存该结果,但是如果另一个用户随后搜索 bar
您仍然需要 运行 对数据库的另一个查询。只有当两个用户搜索 相同的 字符串时,缓存才可能有用。
在您的示例中,数据库中的全文索引可能是更好的选择。
我正在 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
。
因为您仅通过调用需要实际记录的方法(如 each
、to_a
、[=18] 来缓存表示可以 运行 的数据库查询的关系=]) 但还没有 运行,在这种情况下缓存是无用的。
此外,我认为缓存在此示例的上下文中根本没有用,因为您需要为每个不同的用户输入缓存不同的值。这意味着如果用户搜索 foo
那么您可以缓存该结果,但是如果另一个用户随后搜索 bar
您仍然需要 运行 对数据库的另一个查询。只有当两个用户搜索 相同的 字符串时,缓存才可能有用。
在您的示例中,数据库中的全文索引可能是更好的选择。