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 значительную выгоду.
Оригинал статьи на английском:
апреля 24, 2011 at 09:00 (#)
интересная штука…
во втором абзаце предпоследняя строка опечатка
=>возвращается Ъкземпляр
исправьте =)
апреля 24, 2011 at 09:28 (#)
zinenkoan, спасибо, поправил.
апреля 24, 2011 at 11:03 (#)
А еще слово «ключ» пишется без мягкого знака на конце.
апреля 24, 2011 at 12:27 (#)
Это просто отлично! =) У меня недавно возникла проблема, где этого identify map’а реально не хватало. (генерирование ошибок не из модели)
апреля 24, 2011 at 17:37 (#)
У меня тоже с этим проблема была, решение очень не красивое вышло, но костыль всяко лучше, чем когда совсем не работает.
апреля 24, 2011 at 21:08 (#)
Еще раз убеждаюсь в том, что выдается за крутые фичи в RoR уже давно есть по-умолчанию в .NET :)
апреля 25, 2011 at 18:39 (#)
Нечто подобное давно есть в виде CacheMoney. Плюс там есть поддержка кеширования запросов по разным полям.
апреля 25, 2011 at 18:43 (#)
Сразу возникает вопрос, как долго живут оъекты в памяти и сколько это будет стоить памяти.
апреля 26, 2011 at 16:26 (#)
Привет, комменты в примерах кода не до конца еще перевел :)
Рельсы как всегда радуют всякими штукенциями.