mongoid查询缓存

发布于 2024-11-09 07:09:58 字数 274 浏览 0 评论 0原文

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

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

Rails' ActiveRecord has a feature called Query Caching (ActiveRecord::QueryCache) which saves the result of SQL query for the life-span of a request. While I'm not very familiar with the internals of the implementation, I think that it saves the query results somewhere in the Rack env, which is discarded in the end of the request.

The Mongoid, unfortunately, doesn't currently provide such feature, and this is exacerbated by the fact, that some queries occur implicitly (references).
I'm considering to implement this feature, and I'm curious, where and how Mongoid (or, perhaps, mongo driver?) should be hooked in order to implement this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

深爱不及久伴 2024-11-16 07:09:59

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

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

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

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

最后,我想说,一般来说,缓存没有真正的区别——在内存中实际上是在内存中!无论它是在应用程序中还是在数据库中。

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

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

Mongoid has caching, described under http://mongoid.org/en/mongoid/docs/extras.html

Also MongoDB itself has caching ability: http://www.mongodb.org/display/DOCS/Caching

The mongoid caching extra knows 2 different cases: Caching of all queries of a model or caching of a query.

Mongoid caching seems to work slightly differently: it looks like mongoid delegates caching to mongodb. (In the sources of mongoid I only can find option settings for caching but no cache module.)

Finally, I would say, there is no real difference in the caching in general -- in memory is in fact in memory! No matter if it's in the app or in the database.

I don't prefer to implement an extra caching algorithm, because this seems to be redundant and a RAM killer.

BTW: If your really want to cache results in-app you could try Rails.cache or another cache gem as a workaround.

单身狗的梦 2024-11-16 07:09:59

另一个答案显然是错误的。不仅 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)

The other answer is obviously wrong. Not only mongoid or mongo driver doesn't cache the query, even if mongo would - it still might be on other machine across the network.

My solution was to wrap the receive_message in Mongo::Connection.
Pros: one definite place
Cons: deserialization still takes place


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)
聆听风音 2024-11-16 07:09:59

OK,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 应用程序中的中间件。 (阿瑟·内维斯)

对于轨道:

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

OK, Mongoid 4 supports QueryCache middleware.

Just add middleware in application.rb

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

And then profit:

  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}}

Source:

Mongoid changelog

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

3410 Mongoid now has a query cache that can be used as a middleware in Rack applications. (Arthur Neves)

For Rails:

config.middleware.use(Mongoid::QueryCache::Middleware)
笑梦风尘 2024-11-16 07:09:59

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

您可以通过包装您的查找来在查找上使用它,如下所示:

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

Mongoid 4.0+ now has a QueryCaching module: http://www.rubydoc.info/github/mongoid/mongoid/Mongoid/QueryCache

You can use it on finds by wrapping your lookups like so:

QueryCache.cache { MyCollection.find("xyz") }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文