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

Плюсы/минусы хранения сериализованного хэша против объекта базы данных key/value в ActiveRecord?

Если у меня есть несколько объектов, каждая из которых имеет в основном Profile, что я использую для хранения случайных атрибутов, каковы плюсы и минусы:

  • Сохранение сериализованного хэша в столбце для записи, vs.
  • Сохранение кучи объектов ключа/значения, которые belong_to являются основным объектом.

код

Скажите, что у вас есть записи STI, подобные этим:

class Building < ActiveRecord::Base
  has_one :profile, :as => :profilable
end
class OfficeBuilding < Building; end
class Home < Building; end
class Restaurant < Building; end

Каждый has_one :profile

Вариант 1. Сериализованный хэш

class SerializedProfile < ActiveRecord::Base
  serialize :settings
end

create_table :profiles, :force => true do |t|
  t.string   :name
  t.string   :website
  t.string   :email
  t.string   :phone
  t.string   :type
  t.text     :settings
  t.integer  :profilable_id
  t.string   :profilable_type
  t.timestamp
end

Вариант 2. Магазин ключей/значений

class KeyValueProfile < ActiveRecord::Base
  has_many :settings
end

create_table :profiles, :force => true do |t|
  t.string   :name
  t.string   :website
  t.string   :email
  t.string   :phone
  t.string   :type
  t.integer  :profilable_id
  t.string   :profilable_type
  t.timestamp
end

create_table :settings, :force => true do |t|
  t.string   :key
  t.text     :value
  t.integer  :profile_id
  t.string   :profile_type
  t.timestamp
end

Что бы вы выбрали?

Предположим, что в 99% случаев мне не нужно будет искать пользовательский settings. Просто интересно, каковы компромиссы с точки зрения производительности и вероятности будущих проблем. И количество пользовательских settings, вероятно, будет где угодно от 10-50.

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

Примечание. Мне интересно только с точки зрения РСУБД. Это было бы идеально подходит для MongoDB/Redis/CouchDB/и т.д. но я хочу знать чисто плюсы и минусы в терминах SQL.

4b9b3361

Ответ 1

У меня была та же проблема, но, наконец, принял решение.

Опция сериализации хеширования делает проблему обслуживания. Трудно запросить, расширить или реорганизовать такие данные - любые незначительные изменения требуют миграции, что означает чтение каждой десериализации и сериализации записей, и в зависимости от рефакторинга может произойти исключение сериализации. Я попробовал как двоичную сериализацию, так и JSON - второй легче извлечь и исправить, но все еще слишком много хлопот.

Отдельная таблица настроек - это то, что я пытаюсь использовать сейчас - гораздо проще в обслуживании. Я планирую использовать Preferences gem для того, что в основном делает всю абстракцию для удобства использования. Я не уверен, что он работает с Rails 3 еще - он маленький, поэтому я могу продлить его, если это необходимо.

Обновление Nov 2013

Недавно выпущенный Rails 4 поддерживает отличные новые функции PostgreSQL 9.1+, такие как типы столбцов hstore или json для ваших динамических наборов данных. Ниже приведена статья, в которой описывается использование hstore в Rails 4. Оба типа поддерживают индексирование и расширенные возможности запросов (Json с Pg 9.3). Hstore также доступен пользователям Rails 3 с activerecord-postgres-hstore gem.

Я переношу некоторые некритические таблицы предпочтений в свой проект в hstores. В миграциях я просто обновляю определения таблиц и execute один SQL-запрос в таблице для перемещения данных.

Ответ 2

Я бы рекомендовал просто создать модельный атрибут вызова и иметь каждый из ваших объектов, для которых многие из них has_many. Тогда вам не нужно возиться с сериализацией или чем-то хрупким. Если вы используете синтаксис: join, у вас нет реальных проблем с производительностью.

Сериализация данных в вашей РСУБД почти всегда неразумна. Это больше, чем о запросах, о способности описывать и переносить ваши данные (и сериализация разрушает эту способность).

class Building < ActiveRecord::Base
  has_many :attributes
end

class Attribute < ActiveRecord::Base
   belongs_to :building
end

create_table :attributes, :force => true do |t|
  t.integer :building_id
  t.string :att_name
  t.string :data
  t.timestamp
end

Ответ 3

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

Еще один улов, который я лично испытал при использовании сериализованного хэша, заключается в том, что вы должны быть осторожны, чтобы сериализованные данные, которые вы храните, не больше, чем то, что может содержать текстовое поле DB. Если вы не будете осторожны, вы можете легко потерять или испортить данные. Например, используя описанный вами класс и таблицу SerializedProfile, вы можете вызвать такое поведение:

profile = SerializedProfile.create(:settings=>{})
100.times{ |i| profile.settings[i] = "A value" }
profile.save!
profile.reload
profile.settings.class #=> Hash
profile.settings.size #=> 100

5000.times{ |i| profile.settings[i] = "A value" }
profile.save!
profile.reload
profile.settings.class #=> String
profile.settings.size #=> 65535

Все, что говорит код, помните о своих ограничениях в базе данных, или ваши сериализованные данные будут обрезаны при следующем извлечении, и ActiveRecord не сможет повторно сериализовать его.

Для тех из вас, кто хочет использовать Serialized Hash, пойдите для этого! Я думаю, что в некоторых случаях он может хорошо работать. Я наткнулся на плагин activerecord-attribute-fakers, который кажется подходящим.