ActiveRecord в Rails 3.1 будет снабжен Identity Map

апреля 23, 2011  |  Published in Ruby on Rails, Ruby on Rails 3  |  9 Comments

Если вы являетесь разработчиком на платформе Rails, то вы, должно быть, знакомы с кэшированием запросов в Active Record. Кэширование запросов — очень полезная составляющая Active Record, которая сокращает ненужные SQL запросы и предоставляет значительное увеличение производительности, особенно при обращении к ассоциациям. Поблема с кэшированием запросов, однако, возникает тогда, когда при получении двух идентичных записей из базы данных, мы получаем два объекта в оперативной памяти.

user1 = User.find(1) # => #<User id: 1, name: "Josh">
user2 = User.find(1) # => #<User id: 1, name: "Josh">

user1 == user2 # => true, b/c AR::Base recognizes that
# они имеют одинаковый первичный ключ

user1.object_id == user2.object_id # => false, b/c these are two
# но являются двумя разными объектами


#log/development.log
User Load (0.2ms)  SELECT «users».* FROM «users» WHERE «users».»id» = ? LIMIT 1  [["id", 1]]
CACHE (0.0ms)  SELECT «users».* FROM «users» WHERE «users».»id» = ? LIMIT 1  [["id", 1]]

Благодяря огромной работе Эмилио Тегуа, во время Ruby Summer of Code 2010, Active Record в версии 3.1 разбогатеет поддержкой паттерна Identity Map. Вы можете спросить, что за патерн такой identity map? Согласно этому паттерну, сохраняется коллекция ранее загруженных записей и возвращается экземпляр модели ассоциируемый с записью, если программа вновь пытается запросить эту (уже загруженную) запись.

user1 = User.find(1) # => #<User id: 1, name: "Josh">
user2 = User.find(1) # => #<User id: 1, name: "Josh">

user1 == user2 # => true
user1.object_id == user2.object_id # => true, b/c these really are
# user1 и user2 - ссылки на один и тот же объект

# log/development.log
User Load (2.2ms)  SELECT «users».* FROM «users» LIMIT 1
User with ID = 1 loaded from Identity Map

Почему так важно то, что возвращается тот самый объект? — Потому, что это гарантирует что одновременно в памяти может храниться лишь один экземпляр модели соответствующий определенной записи. Без этого, изменения произведенные с одним объектом, не будут отображены в другом объекте той же самой записи, что приводит к усложнению выявления ошибок и несогласованности работы вашего кода.

Identity map создан на основе каждого запроса и проявляется в конце запроса (как можно было ожидать, реализация identity map является thred-safe, то есть нет проблем с потоками выполнения программы). Вы также можете использовать паттерн identity map в консоли, фоновом воркере или вручную, внутри запроса (если по умолчанию он выключен).

ActiveRecord::IdentityMap.use do
  user = User.find(id)
  user.do_that_heavy_thing_you_do!
end

Хотя фреймворк Rails версии 3.1 увидит свет с уже встроенным и включенным по умолчанию identity map, вы можете поиграться с ним уже сейчас в edge-версии, включив его в application.rb:

config.active_record.identity_map = true

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

Оригинал статьи на  английском: 

Tags: ,

Responses

  1. zinenkoan says:

    апреля 24, 2011 at 09:00 (#)

    интересная штука…

    во втором абзаце предпоследняя строка опечатка
    =>возвращается Ъкземпляр
    исправьте =)

  2. admin says:

    апреля 24, 2011 at 09:28 (#)

    zinenkoan, спасибо, поправил.

  3. rwz says:

    апреля 24, 2011 at 11:03 (#)

    А еще слово «ключ» пишется без мягкого знака на конце.

  4. says:

    апреля 24, 2011 at 12:27 (#)

    Это просто отлично! =) У меня недавно возникла проблема, где этого identify map’а реально не хватало. (генерирование ошибок не из модели)

  5. admin says:

    апреля 24, 2011 at 17:37 (#)

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

  6. says:

    апреля 24, 2011 at 21:08 (#)

    Еще раз убеждаюсь в том, что выдается за крутые фичи в RoR уже давно есть по-умолчанию в .NET :)

  7. potapuff says:

    апреля 25, 2011 at 18:39 (#)

    Нечто подобное давно есть в виде CacheMoney. Плюс там есть поддержка кеширования запросов по разным полям.

  8. potapuff says:

    апреля 25, 2011 at 18:43 (#)

    Сразу возникает вопрос, как долго живут оъекты в памяти и сколько это будет стоить памяти.

  9. says:

    апреля 26, 2011 at 16:26 (#)

    Привет, комменты в примерах кода не до конца еще перевел :)

    Рельсы как всегда радуют всякими штукенциями.

Leave a Response

Для подсветки кода используйте BB - коды: [language]...[/language], где language может быть: ruby, javascript, css, html.