Rails Caching DB Queries and Best Practices

Загрузка БД на моем сайте становится очень высокой, поэтому мне пора кэшировать общие запросы, которые вызываются 1000 раз в час, когда результаты не меняются. Так, например, на моей модели города я делаю следующее:

def self.fetch(id)   
  Rails.cache.fetch("city_#{id}") { City.find(id) }   
end 

def after_save
  Rails.cache.delete("city_#{self.id}")
end

def after_destroy
  Rails.cache.delete("city_#{self.id}")
end

Итак, теперь, когда я могу City.find (1) в первый раз, я попадаю в БД, но следующие 1000 раз я получаю результат из памяти. Большой. Но большинство вызовов city не City.find (1), а @ user.city.name, где Rails не использует выборку, а снова запрашивает БД ... что имеет смысл, но не совсем то, что я хочу.

Я могу использовать City.find (@ user.city_id), но это некрасиво.

Итак, мой вопрос к вам, ребята. Что делают умные люди? Что такое правильный способ сделать это?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
25
0
14 160
4

Ответы 4

Проверить cached_model

мемоизация просто обертывает Rails.cache. Я не думаю, что это поможет модельным ассоциациям, которые вы ищете.

Bill 06.12.2008 01:57

Мемоизация не оборачивает кеш Rails. Rails.cache обычно является хранилищем кэша, совместно используемым между процессами (таким образом, вы фактически получаете преимущества кэширования). Мемоизация происходит только в текущем процессе.

Michael 06.12.2008 08:39

Я бы пошел дальше и взглянул на Мемоизация, который сейчас находится в Rails 2.2.

"Memoization is a pattern of initializing a method once and then stashing its value away for repeat use."

Недавно на нем был замечательный Эпизод Railscast, который должен заставить вас нормально работать.

Быстрый пример кода из Railscast:

class Product < ActiveRecord::Base
  extend ActiveSupport::Memoizable

  belongs_to :category

  def filesize(num = 1)
    # some expensive operation
    sleep 2
    12345789 * num
  end
  memoize :filesize
end

Подробнее о мемоизации

В чем преимущество мемоизации перед Rails.cache и как это решает проблему User.city.name, когда Rails находит в City вместо использования кэшированных данных?

John Kopanas 06.12.2008 00:26

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

Michael 06.12.2008 08:32

По поводу кеширования пара мелких моментов:

Для разделения типа объекта и идентификатора стоит использовать косую черту, что является условным обозначением рельсов. Более того, модели ActiveRecord предоставляют метод экземпляра cacke_key, который предоставляет уникальный идентификатор, состоящий из имени и идентификатора таблицы, «городов / 13» и т. д.

Одно небольшое исправление в вашем фильтре after_save. Поскольку у вас есть данные под рукой, вы можете записать их обратно в кеш, а не удалять. Это сэкономит вам одну поездку в базу данных;)

def after_save
  Rails.cache.write(cache_key,self)
end

Что касается корня вопроса, если вы постоянно нажимаете @ user.city.name, есть два реальных варианта:

  • Перенормализуйте название города пользователя в строку пользователя. @ user.city_name (оставьте внешний ключ city_id). Это значение следует записать во время экономии.

-или же-

  • Реализуйте свой метод User.fetch, чтобы загрузить город. Делайте это только в том случае, если содержимое строки города никогда не меняется (например, имя и т. д.), Иначе вы потенциально можете открыть банку червей в отношении недействительности кеша.

Личное мнение: Реализуйте базовые методы выборки на основе идентификатора (или используйте плагин) для интеграции с memcached и денормализуйте название города в строке пользователя.

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

Если вы получаете слишком много запросов к базе данных, определенно стоит проверить активную загрузку (через: include), если вы еще этого не сделали. Это должно быть первым шагом к уменьшению количества запросов к базе данных.

Например, User.where(id: 3).includes(:city).first. join-merge недооценивается во взаимоотношениях "многие-многие-многие". EG City.joins(:restaurants).merge(user.favorite_restaurants), вернет все города, в которых у пользователя много любимых ресторанов, а у ресторанов много городов. Проверьте включает и присоединяется. Определенно стоит узнать, как сократить количество вызовов с помощью мощных запросов, вместо того, чтобы мучиться с кешированием.

Eric H. 21.05.2015 00:52

Если вам нужно ускорить sql-запросы к данным, которые не сильно меняются со временем, вы можете использовать материализованные представления.

A matview stores the results of a query into a table-like structure of its own, from which the data can be queried. It is not possible to add or delete rows, but the rest of the time it behaves just like an actual table. Queries are faster, and the matview itself can be indexed.

At the time of this writing, matviews are natively available in Oracle DB, PostgreSQL, Sybase, IBM DB2, and Microsoft SQL Server. MySQL doesn’t provide native support for matviews, unfortunately, but there are open source alternatives to it.

Вот несколько хороших статей о том, как использовать matviews в Rails.

sitepoint.com/speed-up-with-materialized-views-on-postgresql-and-rails

hashrocket.com/materialized-view-strategies-using-postgresql

Другие вопросы по теме