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


64

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

  1. 単一行のテーブル

      CompanyName  |  StartFullScreen  |  RefreshSeconds  |  ...
    ---------------+-------------------+------------------+--------
      ACME Inc.    |        true       |       20         |  ...
    
  2. 名前と値のペアのテーブル

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

両方のオプションを実際に見てきましたが、どちらにも明らかな利点と欠点があります。

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

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


2
「垂直」アプローチが異なるデータ型を持つことができない理由はありません。int、float、およびtext列を行ごとに追加します。このような「SaveConfigInt( 『フィールド』、N」)としてタイプ固有の機能、使用してから/負荷値を保存
GrandmasterB

4
これについての優れたStackOverflowの質問があり、一番上の答えは両方のアプローチの長所と短所を示しています。stackoverflow.com/questions/2300356/…–
ケビン

1
アプローチ3:JSONやYAMLなどの単純なデータ交換形式を使用した単一列/単一行。両方のアプローチの利点を組み合わせます。
schlamar

<config> <CompanyName> ACME Inc。</ CompanyName> <StartFullScreen> true </ StartFullScreen> 20 <RefreshSeconds> </ RefreshSeconds> </ config>などのxml / jsonを含む複雑なデータで単一行テーブルを使用する場合ビジネス層のオブジェクトを検証しますか?
ジョン

1
@John:階層構造が必要な場合、良い考えです。そうでない場合は、オプション2に複雑さを追加します。
ハインジ

回答:


15

個人的には、ほとんどの場合、単一行のテーブルを好みます。柔軟性が低いのは事実ですが、動的な動作を想定していない限り、必要に応じて後で列を追加することは完全に受け入れられます。ある意味、これは、辞書/マップを使用して名前と値のペアを保持するのと、プログラミング時にクラスメンバーを保持するのと同じです。確かに、それは完全な比phorではありませんが、それについて考えると、多くの利点と欠点が並行しています。

クラスメンバーに対して辞書/マップを使用しますか?おそらく、表されるデータの量が完全に適応可能であると考える理由がなければ、名前と値のペアテーブルを持っているのと同じです。


保存するデータがユーザー定義の場合はどうなりますか?つまり、ユーザーがフィールドラベル、保持するデータのタイプなどを指定して「フィールド」を作成できるUIを考えてみてください。これは、コードからDDLステートメントを実行することを意味します。あなたはまだオプション1で行きますか?
デバナリスト

1
@devanalystいいえ、データがコンポーネントごとに変わる可能性がある場合、静的テーブルを作成してそれを表すことは意味がありません。その場合、2番目のオプションを使用することをお勧めします。
ニール

12

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

ConfigOption   |   textValue    |   DateValue   |   NumericValue

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


構成を無効にすることを許可する場合(オプション1の場合)、少なくともそれをactivatedOnタイムスタンプにして、いつアクティブ化されかを確認できるようにします。そして、オプション2を使用している場合...最終的に複数の列に値を保存するとどうなりますか(またはoracleの場合、(明らかに)nullと空の文字列は同等です)
時計仕掛けのミューズ

1
@ X-Zero、複数の構成の保存は通常、テスト目的で行われますが、タイムスタンプが傷つくことはありません。コンフィグメンテナンスは、...値は、あなたが本当にしたい場合、あなたはデータ型の列を追加することができ、チェックするためにどのようなコラムを知っているだろう..しかし、私はそれが終わっ殺すだと思う取得するために呼び出す
低能

5
EATV(Entity-Attribute-Type-Value)スキーマは、3番目の標準形式を破ります。Type列は、Type列が記述するValue列を介して、テーブルの主キーに間接的にのみ関連付けられます。さらに、動的な型の保存とインスタンス化ではあまり解決できません。GetConfigValue()メソッドが任意の型を返すことができる場合、Objectを返す(または何らかの方法で予期される型を指定する)必要がありますが、これらは実行時に評価する必要があります。
キース

5
私が見たソフトウェアにオプション1を実装するたびに、オプション2に変換する必要がありました。オプション2は、時間の経過とともに維持しやすく、初めて正しく実装するには少し時間がかかります。オプション1は迅速かつ簡単に実装できますが、ソフトウェアが小さく成長する可能性がない限り、長期にわたるメンテナンスは恐ろしいものです。
ジミー・ホッファ

8

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

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

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

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

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

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

要するに、構成を保存するEAVスキーマは、それが解決しようとする問題を実際には解決せず、それが提示する問題のほとんどの回避策はDRYに違反します。


3

特に構成値については、単一の行で行ってください。現在開発中の場合を除き、これらの列はどのくらいの頻度で変更されますか?

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

さらに、「ユーザー」は上限を設定せずにこれらのオプションを設定できると言いました。ユーザーごとの構成ですか?もしそうなら、構成オプションは列にあるべきだとさらに強く主張します-ユーザーごとに1行です。後で多くのメンテナンスの頭痛の種を節約できます。


2

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

クライアントがJSONフラグメントを処理できない場合、新しいクライアントを取得します。


1

単一行の長所:明確に定義されています。短所:構成を変更するのは大変です。DBの移行など。

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

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


1

両方を使う!

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

単一行テーブル(構成)

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

名前と値のペアのテーブル(オプション)

  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    
  ...              |  ...            | ...          

これはより柔軟だと思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.