кэширование запросов mongoid

#ruby #ruby-on-rails-3 #caching #mongoid #rack

#ruby #ruby-on-rails-3 #кэширование #mongoid #rack

Вопрос:

ActiveRecord от Rails имеет функцию, называемую кэшированием запросов (ActiveRecord::QueryCache), которая сохраняет результат SQL-запроса в течение срока службы запроса. Хотя я не очень знаком с внутренней частью реализации, я думаю, что она сохраняет результаты запроса где-то в Rack env, который отбрасывается в конце запроса.

Mongoid, к сожалению, в настоящее время не предоставляет такой функции, и это усугубляется тем фактом, что некоторые запросы выполняются неявно (ссылки). Я рассматриваю возможность реализации этой функции, и мне любопытно, где и как Mongoid (или, возможно, драйвер mongo?) должно быть подключено для реализации этого.

Ответ №1:

В Mongoid есть кэширование, описанное в http://mongoid.org/en/mongoid/docs/extras.html

Также сам MongoDB обладает возможностью кэширования: http://www.mongodb.org/display/DOCS/Caching

Дополнительное кэширование mongoid знает 2 разных случая: кэширование всех запросов модели или кэширование запроса.

Кэширование Mongoid, похоже, работает немного по-другому: похоже, что mongoid делегирует кэширование mongodb. (В исходных текстах mongoid я могу найти только настройки параметров для кэширования, но нет модуля кэша.)

Наконец, я бы сказал, что нет реальной разницы в кэшировании в целом — in memory на самом деле находится в памяти! Не имеет значения, находится ли это в приложении или в базе данных.

Я не предпочитаю внедрять дополнительный алгоритм кэширования, потому что это кажется избыточным и убивает оперативную память.

Кстати: Если вы действительно хотите кэшировать результаты в приложении, вы могли бы попробовать Rails.cache или другой cache gem в качестве обходного пути.

Комментарии:

1. Большое вам спасибо за ваш ответ. Однако это не отвечает на мой вопрос. Я очень хорошо осведомлен о текущих возможностях кэширования Mongoid, и если вы хотите лучше понять, что он делает в настоящее время, прочтите это, например: groups.google.com/group/mongoid/browse_thread/thread /…

2. Это не причина для снижения голосов; вы должны сделать свой вопрос ясным и понятный.

3. Я полагаю, что этот вопрос довольно ясен, он спрашивает «Как можно реализовать кэш запросов по запросу в mongoid», а не «как мне что-то кэшировать в mongoid». Как бы вы предложили это перефразировать?

Ответ №2:

Другой ответ, очевидно, неверен. Не только mongoid или mongo driver не кэшируют запрос, даже если бы 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)
  

Комментарии:

1. Очень интересно. Не могли бы вы, пожалуйста, привести какой-нибудь пример использования?

2. Поскольку Mongoid 2.4.x имеет карту идентификаторов, вам это больше не нужно.

3. В дополнение к карте идентификации, в Mongoid также теперь встроен кэш запросов: mongoid.org/en/mongoid/docs/extras.html#caching

4. @Roman карта идентификации помогает только при запросе по идентификатору (первичному ключу). Кэш запросов кэширует любой запрос независимо от критериев.

5. @BrianArmstrong «кэш», упомянутый на странице дополнительных функций, не является кэшем запросов. Это просто заставляет 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)
  

Комментарии:

1. При вызове со строкой выдает ошибку, вместо этого используйте config.middleware.use(Mongoid::QueryCache::Middleware) , как указано в документации

Ответ №4:

В Mongoid 4.0 теперь есть модуль кэширования запросов: http://www.rubydoc.info/github/mongoid/mongoid/Mongoid/QueryCache

Вы можете использовать это при поиске, обернув свои запросы следующим образом:

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