Подтвердить что ты не робот

Резервное копирование БД запросов и передовой практики

Загрузка БД на мой сайт становится очень высокой, поэтому мне пора кэшировать общие запросы, которые называются 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.find(1), а @user.city.name, где Rails не использует выборку, но снова запрашивает DB... что имеет смысл, но не совсем то, что я хочу.

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

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

4b9b3361

Ответ 1

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

Стоит использовать слэш для разделения типа объекта и id, что является условным обозначением rails. Более того, модели ActiveRecord предоставляют метод экземпляра cacke_key, который будет предоставлять уникальный идентификатор имени и идентификатора таблицы, "городов/13" и т.д.

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

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

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

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

-or-

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

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

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

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

Ответ 2

Я бы пошел и посмотрю 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

Подробнее о Memoization

Ответ 3

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

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

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

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

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

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