Rails Caching DB Запросы и лучшие практики - PullRequest
24 голосов
/ 05 декабря 2008

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

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), но это ужасно.

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

Ответы [ 4 ]

23 голосов
/ 06 декабря 2008

Что касается кеширования, пара незначительных баллов:

Стоит использовать косую черту для разделения типа объекта и идентификатора, что является соглашением о рельсах. Более того, модели ActiveRecord предоставляют метод экземпляра cacke_key, который предоставит уникальный идентификатор имени и идентификатора таблицы, "towns / 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), если вы еще этого не сделали. Это должно стать первым шагом к сокращению количества запросов к базе данных.

0 голосов
/ 15 апреля 2017

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

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

На момент написания этой статьи matviews изначально были доступны в Oracle. БД, PostgreSQL, Sybase, IBM DB2 и Microsoft SQL Server. MySQL к сожалению, не предоставляет встроенную поддержку matviews, но есть являются альтернативами с открытым исходным кодом.

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

sitepoint.com / скорость-до-с-материализовались-видовые на-и-PostgreSQL контррельсы

hashrocket.com / материализовался-View-стратегии, используя-* PostgreSQL 1016 *

0 голосов
/ 05 декабря 2008

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

"Мемоизация является паттерном инициализировать метод один раз, а затем спрятать его значение для повторения использовать. "

Недавно на нем был отличный эпизод 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

Подробнее о памятке

0 голосов
/ 05 декабря 2008

Оформить заказ cached_model

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...