查询缓存
MongoDB Ruby 驱动程序提供了一个内置的查询缓存。当启用时,查询缓存会保存之前执行的 find 和聚合查询的结果。当再次执行相同的查询时,驱动程序会返回缓存的查询结果,以防止不必要的数据库往返。
用法
查询缓存默认是禁用的。它可以在全局范围内以及特定块上下文中启用。驱动程序还提供了一个Rack 中间件来自动为每个网络请求启用查询缓存。
要全局启用查询缓存
Mongo::QueryCache.enabled = true
同样,要全局禁用它
Mongo::QueryCache.enabled = false
要在块上下文中启用查询缓存
Mongo::QueryCache.cache do Mongo::Client.new([ '127.0.0.1:27017' ], database: 'music') do |client| client['artists'].find(name: 'Flying Lotus').first #=> Queries the database and caches the result client['artists'].find(name: 'Flying Lotus').first #=> Returns the previously cached result end end
并在块上下文中禁用查询缓存
Mongo::QueryCache.uncached do Mongo::Client.new([ '127.0.0.1:27017' ], database: 'music') do |client| client['artists'].find(name: 'Flying Lotus').first #=> Sends the query to the database; does NOT cache the result client['artists'].find(name: 'Flying Lotus').first #=> Queries the database again end end
您可以通过调用Mongo::QueryCache.enabled?
来检查查询缓存是否启用,这将返回 true
或 false
。
与纤维的交互
查询缓存启用标志存储在纤维本地存储中(使用 Thread.current)。从原则上讲,这允许查询缓存状态是针对每个纤维的,尽管目前尚未进行测试。
Ruby标准库中存在一些方法,例如Enumerable#next
,它们的实现中使用纤维。当应用程序设置查询缓存启用标志时,这些方法不会看到它,并且不会使用查询缓存。例如,以下代码即使请求了查询缓存,也没有使用它:
Mongo::QueryCache.enabled = true client['artists'].find({}, limit: 1).to_enum.next # Issues the query again. client['artists'].find({}, limit: 1).to_enum.next
将此代码重写为使用first
而不是next
将使其使用查询缓存
Mongo::QueryCache.enabled = true client['artists'].find({}, limit: 1).first # Utilizes the cached result from the first query. client['artists'].find({}, limit: 1).first
查询匹配
如果查询与产生缓存结果的原查询匹配,则可以使用缓存结果。以下值相同的两个查询被视为匹配:
命名空间(执行查询的数据库和集合)
选择器(对于聚合,聚合管道阶段)
跳过
排序
投影
排序规则
读取关注点
读取偏好
例如,如果您执行了一个查询,然后执行了一个与排序顺序不同的类似查询,这些查询将不会被视作匹配,第二个查询将不会使用第一个查询的缓存结果。
限制
执行带限制的查询时,如果存在具有较大限制的现有缓存查询,查询缓存将重用该查询。例如
Mongo::QueryCache.cache do Mongo::Client.new([ '127.0.0.1:27017' ], database: 'music') do |client| client['artists'].find(genre: 'Rock', limit: 10) #=> Queries the database and caches the result client['artists'].find(genre: 'Rock', limit: 5) #=> Returns the first 5 results from the cached query client['artists'].find(genre: 'Rock', limit: 20) #=> Queries the database again and replaces the previously cached query results end end
缓存失效
每次写操作都会部分或全部清除查询缓存。大多数写操作将清除在写入的同一集合上执行的任何查询的结果。某些操作将清除整个查询缓存。
以下操作将在相同数据库和集合上清除缓存查询结果(包括在批量写入期间)
insert_one
update_one
replace_one
update_many
delete_one
delete_many
find_one_and_delete
find_one_and_update
find_one_and_replace
以下操作将清除整个查询缓存
使用
$merge
或$out
管道阶段的聚合操作提交事务
中止事务
手动缓存失效
您可以使用以下方法随时清除查询缓存
Mongo::QueryCache.clear
这将删除所有缓存的查询结果。
事务
查询在事务的上下文中进行缓存,但在提交或中止事务时,整个缓存将被清除。
Mongo::QueryCache.cache do Mongo::Client.new([ '127.0.0.1:27017' ], database: 'music') do |client| session = client.start_session session.with_transaction do client['artists'].insert_one({ name: 'Fleet Foxes' }, session: session) client['artists'].find({}, session: session).first #=> { name: 'Fleet Foxes' } #=> Queries the database and caches the result client['artists'].find({}, session: session).first #=> { name: 'Fleet Foxes' } #=> Returns the previously cached result session.abort_transaction end client['artists'].find.first #=> nil # The query cache was cleared on abort_transaction end end
注意
事务通常与“快照”读取关注级别一起执行。请注意,具有“快照”读取关注级别的查询无法返回没有“快照”读取关注级别的查询的缓存结果,因此事务可能不会使用先前缓存的查询。
要了解查询何时将使用缓存结果,请参阅查询匹配部分。
聚合
查询缓存还会缓存聚合管道的结果。例如
Mongo::QueryCache.cache do Mongo::Client.new([ '127.0.0.1:27017' ], database: 'music') do |client| client['artists'].aggregate([ { '$match' => { name: 'Fleet Foxes' } } ]).first #=> Queries the database and caches the result client['artists'].aggregate([ { '$match' => { name: 'Fleet Foxes' } } ]).first #=> Returns the previously cached result end end
注意
在每次写入操作期间,都会从缓存中清除聚合结果,没有例外。
系统集合
MongoDB将系统信息存储在遵循database.system.*
命名空间模式的集合中。这些被称为系统集合。
系统集合中的数据可能会由于应用程序(如内部服务器进程)触发的活动以及应用程序发出的各种数据库命令而发生变化。由于难以确定何时应该使系统集合的缓存结果过期,因此对系统集合的查询会绕过查询缓存。
您可以在MongoDB文档中了解更多有关系统集合的信息:MongoDB文档。
注意
即使在查询缓存启用的情况下,系统集合的查询结果也不会被缓存。
查询缓存中间件
Rack中间件
驱动程序提供了一种Rack中间件,它可以在每个Web请求期间启用查询缓存。以下是在Ruby on Rails应用程序中启用查询缓存中间件的示例
# config/application.rb # Add Mongo::QueryCache::Middleware at the bottom of the middleware stack # or before other middleware that queries MongoDB. config.middleware.use Mongo::QueryCache::Middleware
请参阅Rails on Rack指南,了解如何在Rails应用程序中使用Rack中间件。
Active Job中间件
该驱动程序提供了一种Active Job中间件,可以为每个作业启用查询缓存。以下是在Ruby on Rails应用程序中启用查询缓存Active Job中间件的示例:
# config/application.rb ActiveSupport.on_load(:active_job) do include Mongo::QueryCache::Middleware::ActiveJob end