web-dev-qa-db-ja.com

フィールドタイプデータベース設計のベストプラクティス

ユーザーがWebサイトのテンプレートで使用するフィールドを作成できるcmsシステムを作成しています。 'string'、 'html'、 'integer'などのさまざまなタイプを作成したい。ユーザーはこれらのフィールドをさまざまな値で追加できる必要があるため、少なくとも2つのテーブルが必要になります。

私の質問はこれです:フィールド値タイプごとにテーブルを作成してコードでこれをキャッチする必要がありますか、それともすべてのフィールド値タイプを1つのテーブルに格納する必要がありますか?

オプション1:各タイプのテーブル

+---------------+    +-----------------+    +--------------------+
| Fields        |    | field_int_value |    | field_string_value |    etc...
+---------------+    +-----------------+    +--------------------+
| id            |    | field_id        |    | field_id           |
| field_type_id |    | language_id     |    | language_id        |
+---------------+    | value (int)     |    | value (varchar)    |
                     +-----------------+    +--------------------+

オプション2: 1つのテーブルにすべての値を格納します。未使用の値をNULLのままにします。

+---------------+    +-----------------+
| Fields        |    | field_value     |
+---------------+    +-----------------+
| id            |    | field_id        |
| field_type_id |    | language_id     |
+---------------+    | value_int       |
                     | value_string    |
                     | etc...          |
                     +-----------------+

いくつかの例:

たとえば、ユーザーは自分の電話番号を使用して文字列を作成できます。コードでは、テンプレートはこのフィールドを呼び出して電話番号を表示します。ユーザーがこれを変更する場合は、テンプレートの編集について心配することなく、管理者で値を編集するだけで済みます。

もう1つの例は、ユーザーがページに特定の「行動を促すフレーズ」を表示できるようにするブール値です。このブール値は、テンプレートを更新せずにテンプレート内の何かを非表示にするために使用されます。

私のフィールドモデルは、これらすべてを処理するモデルになります。ここでは、特定のタイプのフィールドを取得する関数を作成します。


私は何が最善の選択肢であるかについて頭を悩ませてきましたが、より良い選択肢を見つけることができないようです。誰かアイデアはありますか?

3
Jerodev

このデータをRDBMS以外の場所に保存するという、@ gbnの提案(質問へのコメント)を軽視しないでください。RDBMSルートを使用することにした場合は、列のある単一のテーブルを使用する方がよいと思います。強く型付けできるように、「型」ごとに。または、すべてのデータを文字列に変換/シリアル化できるため、couldは、単一の文字列フィールドを持つ単一のテーブルを使用できますが、注意が必要です。すべての操作で両方向に適切に変換を行うため。そのテーブルの一部の使用が誤って変換されるか、完全に変換するのを忘れた場合、問題が発生する可能性があります。

単一のテーブルを選択する理由は、ほとんどがロジスティクスです。TypeIDに基づくクエリで異なるテーブルから動的にプルするよりも、COALESCEまたはCASE(またはCASEのような)句に基づいて異なる列を動的に選択する方がはるかに簡単です。行の(少なくとも、すべてのクエリですべての「タイプ」テーブルをLEFT JOINする必要がないわけではありません(そうです!)。

使用しているRDBMSによっては、このモデルを支援するベンダー固有の機能が存在する場合もあります。たとえば、バージョン2008以降のSQL Serverには、NULL可能列に追加できるSPARSEオプションがあると思います。これにより、NULL値が0バイトを占めることが可能になりますが、通常、固定長フィールド(つまり、[N]VAR{something}または{something} VARYINGまたはXMLではないほとんどすべてのフィールドまたは一般的にtextまたはSQL_VARIANT)の場合、常に指定されたバイト数を使用します。欠点は、NULL以外の値の場合、行ごとに4バイト余分に使用されることです。ただし、列がすべての行で75%以上NULLの場合は、巨大な節約になる可能性があります。この機能は、このタイプのモデルに対応するために特別に設計されました。

CHECK CONSTRAINTがあることを確認して、すべてのvalue_フィールドについて、フィールドがないか、1つだけがNOT NULLであることを確認してください。

次に、次のような方法でアクセスできます。

COALESCE(value_int, value_string, value_datetime, etc.)

また、SQL Serverを使用している場合(および1つ以上の他のベンダーがこの機能を備えている場合)、「フィルター処理されたインデックス」を使用して、その値がnullでない特定の各value_フィールドにインデックスを付けることができます。

CREATE NONCLUSTERED INDEX [IX_FieldValues_ValueInt]
  ON dbo.[FieldValues] ([ValueInt])
  WHERE [ValueInt] IS NOT NULL;

これにより、一般的なCOALESCEアクセス方法を使用する場合ではなく、特定のValue%フィールドをターゲットにする場合でも、値を持つ行をターゲットにすることができます。

そして、2つのオプションをもう一度見てみると、実際には、単一のテーブルであるオプションを使用します。 オプション2では、データは実際にはfield_type_idデータの親ではないため、field_valueを分割する目的はあまりないようです。 field_idは単一の値しか持てませんよね?したがって、field_type_idfield_valueテーブルに配置するだけです。そして、それをCHECK CONSTRAINTで使用して、最大で1つのフィールドがNOT NULLであることを確認し、NOTNULLである1つのフィールドがfield_type_idと一致することを確認します。

3
Solomon Rutzky

最良の設計があるかどうかはわかりませんが、私はいくつかの内部に隠れており、データ型ごとに別々のテーブルを使用していました。また、単一値と複数値の別々のテーブルもあります。

私は確かに複数のテーブルで行きます。列名またはテーブル名/結合を選択する必要があるため、それほど複雑ではありません。ビューを使用することもできます。更新には、より具体的なロックが必要です。

複数の値を検討してください。 joeとsueの両方への電子メールをサポートしたい場合はどうでしょうか。特定のテーブルはオーバーヘッドですが、単純なデータモデルで多くのことを行うのは困難です。

サポートを検討する必要がある仕様があります [〜#〜] cmis [〜#〜] 。明らかに、仕様をサポートする必要はありませんが、相互運用性が必要な場合は、それが最善の方法です。

ただし、CMISをサポートせず、ドキュメント(SQLなし)タイプのバックエンドを持つプレーヤーもいます。

そこにいくつかの素晴らしい無料のオープンソースCMSがあります。

0
paparazzo

オプション1と2の違いは、クラステーブル継承と単一テーブル継承の違いのように見えます。これらは、テーブルデザインで継承を模倣する2つの異なる方法です。 2つの手法のトレードオフを調べたい場合は、MartinFowlerによる主題の扱いを調べることをお勧めします。

それらの要約を見ることができます ここ および ここ

より多くの回答を得るために、このタグを質問に追加することもできます。 サブタイプ

0
Walter Mitty