web-dev-qa-db-ja.com

構成データ:単一行のテーブルと名前と値のペアのテーブル

ユーザーが設定できるアプリケーションを作成するとします。この「構成データ」をデータベースに格納するには、2つのパターンが一般的に使用されます。

  1. 単一行テーブル

      CompanyName  |  StartFullScreen  |  RefreshSeconds  |  ...
    ---------------+-------------------+------------------+--------
      ACME Inc.    |        true       |       20         |  ...
    
  2. name-value-pairテーブル

      ConfigOption   |   Value
    -----------------+-------------
     CompanyName     | ACME Inc.
     StartFullScreen | true (or 1, or Y, ...)
     RefreshSeconds  | 20
     ...             | ...
    

私は実際に両方のオプションを見てきました。たとえば、どちらにも明らかな長所と短所があります。次に例を示します。

  • 単一行のテーブルは、使用できる構成オプションの数を制限します(行の列の数は通常制限されているため)。追加の構成オプションごとに、DBスキーマの変更が必要です。
  • 名前と値のペアのテーブルでは、すべてが「文字列型」です(ブール値/日付などのパラメーターをエンコード/デコードする必要があります)。
  • (もっとたくさん)

開発コミュニティ内で、どのオプションが望ましいかについてコンセンサスがありますか?

65
Heinzi

私はほとんどの場合、単一行のテーブルを好みます。柔軟性が低いことは事実ですが、動的な動作を期待している場合を除いて、必要に応じて後で列を追加することは完全に許容されます。ある意味では、これは、辞書/マップを使用して名前と値のペアを保持することと、プログラミング時にクラスメンバーを持つことと同じです。確かに、これは完全な比喩ではありませんが、考えてみると、多くの長所と短所が並行しています。

クラスのメンバーに対して辞書/マップを使用しますか?名前と値のペアテーブルのように、表現するデータの量が完全に適応可能であると考える理由がない限り、おそらくそうではありません。

16
Neil

通常はオプション2を使用しますが、データ型を適用するために複数の列を使用します

ConfigOption   |   textValue    |   DateValue   |   NumericValue

オプション1には、Active列を追加することで構成全体を非常に簡単に「スワップ」できるという追加の利点があります。

12
Morons

私にとって、単一列にするかEAVにするかは、それらをどのように消費するかによって異なります。

EAVの強みは、構造を変更せずに新しいデータを追加できることです。つまり、新しい構成値が必要な場合は、それをテーブルに追加して、コード内の必要な場所に引き出すだけで、ドメイン、スキーマ、マッピング、DALクエリに新しいフィールドを追加する必要がありません。 、など.

その欠点は、データが最も悲惨な方法で処理する必要がある、構造が最も乏しいことです。構成値のすべての使用は、値が存在しないか、または適切な形式ではないことを期待し、存在しない場合にそれに応じて動作する必要があります。構成値は、double、int、またはcharに解析できない場合があります。 nullの可能性があります。値の行がまったくない場合があります。これを回避する方法は通常、特定のコード内タイプのすべての構成値に対して存在する単一の有効な「デフォルト」値を必要とします(極端にまれです。多くの場合、デフォルト値はコードを消費するのと同じくらい問題になります)まったくない)、またはデフォルト値のハードコードされた辞書を保持する(新しい列が追加されるたびに変更する必要があるため、EAVストレージの主な利点はかなり問題になります)。

単一の広い行は、ほぼ逆です。存在するすべての構成値のフィールド/プロパティを使用して、構成オブジェクトの単一のインスタンスにマッピングします。コンパイル時にこれらの値がどのタイプであるかを正確に把握しており、構成列が存在しないか、適切なタイプの値がない場合は、DALで「失敗」し、例外をキャッチするための1つの場所を提供します。構成の取得/ハイドレーションの問題。

主な欠点は、新しい値ごとに構造の変更が必要になることです。新しいDB列、DALの新しい列(マッピングまたはSQLクエリ/ SPのいずれか)、新しいドメイン列。すべて、使用状況を適切にテストするために必要です。

これらのいずれかを使用する適切な状況は、デメリットが軽減される状況です。私にとって、構成コーディングのほとんどの状況では、単一行の実装が必要でした。これは主に、プログラムの一部の動作を制御するまったく新しい構成値を導入する場合、コードをseに変更する必要があるためです。設定オブジェクトとadd使用する値にポップオーバーしないのはなぜですか?

つまり、構成を格納するEAVスキーマは、それが解決しようとしている問題を実際に解決するものではなく、それが示す問題の回避策のほとんどはDRYに違反しています。

8
KeithS

具体的に構成値の場合、私は1行で実行します。現在開発を行っている場合を除き、これらの列はどれくらいの頻度で変更されますか?

大規模な(r)リリース間のダウンタイムで発生する可能性のない拡張性のためのコードではなく、valuesのデータ型を保護することをお勧めします。さらに、単一の列を追加または削除することは、移行が最も簡単なことです。新しい構成オプションを作成するときに頭痛の種はありません。

さらに、「ユーザー」はこれらのオプションを、上限を付けずに設定できると述べました。ユーザーごとの構成ですか?その場合は、構成オプションを列に含める必要があることをさらに強く主張します(ユーザーごとに1行)。後で多くのメンテナンスの頭痛を軽減します。

3
Izkata

クライアントがJSONフラグメント(配列と辞書だけでなく、プレーンな文字列、数値、ブール値、null値も)を処理できる場合、オプション名とJSONを含む文字列値を持つ複数行のテーブルを作成できます。これにより、構造化された値を格納することもでき、これらを処理するためのコードはすでにそこにあるはずです。

クライアントがJSONフラグメントを処理できない場合は、新しいクライアントを取得してください。

2
gnasher729

単一行の長所:明確に定義されています。短所:構成を変更するのは面倒です。 DBマイグレーションなど.

Entity-Value Pro:非常に柔軟で、構成の進化をサポートします。短所:参照整合性?コードをさらにチェックして、プロパティに対して何かを行う前に、そのプロパティが存在するかどうかを確認します。

Mongoのような非リレーショナルデータベースに裏打ちされたアプローチ2を採用します。確かなことがあれば、その変化。

1
JVXR

両方を使う!

複数のインスタンスを持つことができるオプションと、一般的なオプションを分類します。

単一行テーブル(構成)

  id  |  company_name  |  start_fullscreen  |  refresh_seconds  |  ...
------+----------------+--------------------+-------------------+-------
  4   |  ACME Inc.     |  true              |  20               |  ...

名前と値のペアのテーブル((options)

  name             |  value          | update_time  
-------------------+-----------------+--------------
  generic_option_1 |  Option 1 Value | timestamp    
  generic_option_2 |  Option 2 Value | timestamp    
  generic_option_3 |  Option 3 Value | timestamp    
  configuration    |  4              | timestamp    
  ...              |  ...            | ...          

これはもっと柔軟だと思います。

1
Andrew Luca