【问题标题】:mongoid query cachingmongoid 查询缓存
【发布时间】:2011-09-01 00:42:30
【问题描述】:

Rails 的 ActiveRecord 有一个称为查询缓存 (ActiveRecord::QueryCache) 的功能,它可以在请求的生命周期内保存 SQL 查询的结果。虽然我对实现的内部不是很熟悉,但我认为它将查询结果保存在 Rack env 中的某个位置,在请求结束时会被丢弃。

不幸的是,Mongoid 目前不提供这样的功能,而某些查询隐式发生(引用)的事实加剧了这种情况。 我正在考虑实现这个功能,我很好奇,为了实现这个功能,应该在哪里以及如何挂钩 Mongoid(或者,也许是 mongo 驱动程序?)。

【问题讨论】:

    标签: ruby ruby-on-rails-3 caching mongoid rack


    【解决方案1】:

    Mongoid 有缓存,在http://mongoid.org/en/mongoid/docs/extras.html 下描述

    另外MongoDB本身也有缓存能力:http://www.mongodb.org/display/DOCS/Caching

    mongoid 缓存额外知道 2 种不同的情况:缓存模型的所有查询或缓存查询。

    Mongoid 缓存的工作方式似乎略有不同:它看起来像 mongoid 将缓存委托给 mongodb。 (在 mongoid 的源代码中,我只能找到缓存的选项设置,但没有缓存模块。)

    最后要说的是,缓存在一般情况下并没有真正的区别——在内存中实际上就是在内存中!无论是在应用程序中还是在数据库中。

    我不喜欢实现额外的缓存算法,因为这似乎是多余的并且是 RAM 杀手。

    顺便说一句:如果您真的想在应用程序中缓存结果,您可以尝试使用 Rails.cache 或其他缓存 gem 作为解决方法。

    【讨论】:

    • 非常感谢您的回复。但是,这并不能回答我的问题。我非常了解 Mongoid 当前的缓存功能,如果您想更好地了解它当前的功能,请阅读以下内容,例如:groups.google.com/group/mongoid/browse_thread/thread/…
    • 这不是投反对票的理由;你应该让你的问题清晰易懂。
    • 我相信这个问题很清楚,它问的是“如何在 mongoid 中实现每个请求的查询缓存”,而不是“我如何在 mongoid 中缓存一些东西”。您建议如何改写它?
    【解决方案2】:

    另一个答案显然是错误的。不仅 mongoid 或 mongo 驱动程序不会缓存查询,即使 mongo 会 - 它仍然可能在网络上的其他机器上。

    我的解决方案是将receive_message 包装在Mongo::Connection 中。 优点:一个明确的地方 缺点:反序列化仍在进行中

    
    require 'mongo'
    module Mongo
      class Connection
        module QueryCache
          extend ActiveSupport::Concern
    
          module InstanceMethods
    
            # Enable the selector cache within the block.
            def cache
              @query_cache ||= {}
              old, @query_cache_enabled = @query_cache_enabled, true
              yield
            ensure
              clear_query_cache
              @query_cache_enabled = old
            end
    
            # Disable the selector cache within the block.
            def uncached
              old, @query_cache_enabled = @query_cache_enabled, false
              yield
            ensure
              @query_cache_enabled = old
            end
    
            def clear_query_cache
              @query_cache.clear
            end
    
            def cache_receive_message(operation, message)
              @query_cache[operation] ||= {}
              key = message.to_s.hash
              log = "[MONGO] CACHE %s"
              if entry = @query_cache[operation][key]
                Mongoid.logger.debug log % 'HIT'
                entry
              else
                Mongoid.logger.debug log % 'MISS'
                @query_cache[operation][key] = yield
              end
            end
    
            def receive_message_with_cache(operation, message, log_message=nil, socket=nil, command=false)
              if query_cache_enabled
                cache_receive_message(operation, message) do
                  receive_message_without_cache(operation, message, log_message, socket, command)
                end
              else
                receive_message_without_cache(operation, message, log_message, socket, command)
              end
            end
          end # module InstanceMethods
    
          included do
            alias_method_chain :receive_message, :cache
            attr_reader :query_cache, :query_cache_enabled
          end
        end # module QueryCache
      end # class Connection
    end
    
    Mongo::Connection.send(:include, Mongo::Connection::QueryCache)
    

    【讨论】:

    • 非常有趣。能否请您提供一些使用示例?
    • 由于 Mongoid 2.4.x 有一个身份映射,你不再需要这个。
    • 除了identity map,Mongoid现在还内置了查询缓存:mongoid.org/en/mongoid/docs/extras.html#caching
    • @Roman 身份映射仅在您通过 id(主键)查询时才有帮助。无论条件如何,查询缓存都会缓存任何查询。
    • @BrianArmstrong Extras 页面上提到的“缓存”不是查询缓存。它只是使 Mongoid 立即检索所有结果,而不是在使用游标迭代结果集时懒惰地逐个检索每个结果。
    【解决方案3】:

    好的,Mongoid 4 支持 QueryCache 中间件。

    只需在application.rb中添加中间件

    config.middleware.use "Mongoid::QueryCache::Middleware"
    

    然后盈利:

      MOPED: 127.0.0.1:27017 QUERY        database=XXX collection=page_variants selector={"$query"=>{"_id"=>BSON::ObjectId('5564dabb6d61631e21d70000')}, "$orderby"=>{:_id=>1}} flags=[] limit=-1 skip=0 batch_size=nil fields=nil runtime: 0.4397ms
      MOPED: 127.0.0.1:27017 QUERY        database=XXX collection=page_variants selector={"$query"=>{"_id"=>BSON::ObjectId('5564dacf6d61631e21dc0000')}, "$orderby"=>{:_id=>1}} flags=[] limit=-1 skip=0 batch_size=nil fields=nil runtime: 0.4590ms
      QUERY CACHE                         database=XXX collection=page_variants selector={"$query"=>{"_id"=>BSON::ObjectId('5564c9596d61631e21d30000')}, "$orderby"=>{:_id=>1}}
      QUERY CACHE                         database=XXX collection=page_variants selector={"$query"=>{"_id"=>BSON::ObjectId('5564dabb6d61631e21d70000')}, "$orderby"=>{:_id=>1}}
    

    来源:

    Mongoid 更新日志

    https://github.com/mongoid/mongoid/blob/master/CHANGELOG.md#new-features-2

    3410 Mongoid 现在有一个查询缓存,可以用作 Rack 应用程序中的中间件。 (亚瑟·内维斯)

    对于 Rails:

    config.middleware.use(Mongoid::QueryCache::Middleware)
    

    【讨论】:

    • 如果用字符串调用它会出错,而不是像文档所说的那样使用config.middleware.use(Mongoid::QueryCache::Middleware)
    【解决方案4】:

    Mongoid 4.0+ 现在有一个 QueryCaching 模块:http://www.rubydoc.info/github/mongoid/mongoid/Mongoid/QueryCache

    你可以通过像这样包装你的查找来使用它:

    QueryCache.cache { MyCollection.find("xyz") }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-25
      • 2014-05-19
      • 2016-10-02
      相关资源
      最近更新 更多