17

それぞれが基本的に を持つ複数のオブジェクトがある場合Profile、ランダムな属性を格納するために使用しているもの、長所と短所は何ですか:

  1. シリアル化されたハッシュをレコードの列に格納することと、
  2. 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% の確率で custom で検索する必要はないと仮定しますsettings。パフォーマンスと将来の問題の可能性に関して、どのようなトレードオフがあるのか​​ 疑問に思っています. カスタムの数はsettings、10 ~ 50 の範囲である可能性があります。

ActiveRecord のオブジェクト指向の規則に従っているため、設定テーブルを使用する 2 番目のオプションを使用したいと思います。しかし、このような状況では、パフォーマンス コストが高すぎるのではないかと考えています。

注: RDBMS に関してのみ疑問に思っています。これは、MongoDB/Redis/CouchDB などに最適です。しかし、私は純粋にSQLの長所と短所を知りたい.

4

3 に答える 3

13

私は同じ問題を抱えていましたが、最終的に決定を下しました。

ハッシュのシリアル化オプションにより、メンテナンスの問題が発生します。このようなデータのクエリ、拡張、またはリファクタリングは困難です。微妙な変更には移行が必要です。つまり、各レコードのデシリアライズとシリアライズの読み取りが必要であり、リファクタリングによってはシリアライズ例外が発生する可能性があります。バイナリ シリアライゼーションと JSON の両方を試しました。

個別の設定テーブルは、私が今使用しようとしているものです-維持するのがはるかに簡単です. 簡単に使用できるように、ほとんどすべての抽象化を行うものには、Preferences gemを使用する予定です。Rails 3 で動作するかどうかはまだわかりません。小さいので、必要に応じて拡張できます。

2013 年 11 月の更新

最近リリースされた Rails 4 は、動的データ セットのhstorejson列タイプなど、PostgreSQL 9.1+ の優れた新機能をサポートしています。これは、 Rails 4 での hstore の使用法をカバーする記事です。どちらのタイプも、インデックス作成と高度なクエリ機能をサポートしています (Json with Pg 9.3)。Hstore は Activerecord -postgres-hstore gemを使用して Rails 3 ユーザーも利用できます。

プロジェクト内の重要でない設定テーブルの一部を hstores に移行中です。execute移行では、テーブル定義とテーブルごとに 1 つの SQL クエリを更新してデータを移動するだけです。

于 2010-09-13T15:13:27.437 に答える
4

モデル呼び出しAttributeを作成し、それらの多くを必要とする各オブジェクトにhas_manyを含めることをお勧めします。そうすれば、シリアル化やそのような脆弱なものをいじくり回す必要はありません。:join構文を使用する場合、これに関する実際のパフォーマンスの問題はありません。

データをRDBMSにシリアル化することは、ほとんどの場合賢明ではありません。それはクエリ以上のものであり、データを記述して移行する機能に関するものです(そしてシリアル化はその機能を粉砕します)。

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
于 2010-09-13T03:33:52.830 に答える
2

私はあなたが説明したのと同じジレンマに直面していましたが、他の人が言及した潜在的なメンテナンスの利点のために、キー/値テーブルの実装に行き着きました。単一のシリアル化されたハッシュとは対照的に、将来の移行でデータベースの別々の行の情報を選択して更新する方法を考える方が簡単です.

シリアライズされたハッシュを使用するときに私が個人的に経験したもう 1 つの問題は、格納するシリアライズされたデータが 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

DB 制限に注意してください。そうしないと、シリアル化されたデータが次に取得されたときにクリップされ、ActiveRecord が再シリアル化できなくなります。

シリアライズされたハッシュを使用したい場合は、ぜひお試しください。場合によってはうまくいく可能性もあると思います。私はちょうどいいと思われるactiverecord-attribute-fakers プラグインを偶然見つけました。

于 2010-12-23T00:27:33.943 に答える