web-dev-qa-db-ja.com

ユーザー定義フィールドを許可することは悪い習慣ですか?

一般的に言えば、Webアプリケーションのデータベースでユーザーが作成したフィールドを許可することは悪い習慣と考えられていますか?

たとえば、妻のために住宅在庫Webアプリケーションを作成していて、妻はさまざまなアイテムに対して独自のフィールドを定義したいと考えています。彼女がアイテムのカテゴリを作成して、それらのカテゴリに「機能」を追加できるようにすることを計画していました。機能は、文字列として格納されたキー/値です。たとえば、「オーディオCD」というカテゴリがある場合、「アーティスト」、「トラック」などの機能を追加できます。「家具」などの別のカテゴリでは、「素材」などの機能を追加できます。 "(木材、プラスチックなど)。次に、どのアイテムも1つ(または複数)のカテゴリに属し、それらの機能をアイテムに追加できます。

これらの機能による検索では文字列の比較が必要な、データの検証がないなどの問題が見られます。アジャイルな方法論に従うと、彼女に新しいカテゴリと属性を考えさせて、新しいテーブルを作成するだけで済むようになるでしょう。私たちが行くにつれて。私の例では、それは小さなユーザーベース(2人)であり、作成されるレコードの量は少ないので、それほど悪くはありません。

しかし一般的に言えば、人々はこのようなものを「現実の生活」でどのように扱うのでしょうか?

17
zako42

バグ追跡、顧客リソース管理、および同様のビジネスツールでよく見られる「ユーザー定義フィールド」に取り掛かると、それらはバジリオンフィールドを持つテーブルでサポートされていません(そうである場合、それはおそらく問題です)それ自身)。

代わりに、 エンティティ属性値 テーブル設計と、有効な属性を管理するための関連する管理ツールが見つかります。

次の表を検討してください。

 
 + -------------- + 
 |事| 
 | ----------- | id | 
 |タイプ| 
 | desc | 
 | attr1 | 
 | attr2 | 
 | attr3 | 
 | attr4 | 
 | attr5 | 
 + -------------- + 

これは、いくつかの属性を追加した後です。の代わりに attr1artistまたはtracksまたはgenreまたは物が持つあらゆる属性を読み取るふりをします。そして、5の代わりに、50だったとしたらどうでしょう。明らかにそれは管理不可能です。新しいフィールドを処理するには、モデルの更新とアプリケーションの再デプロイメントも必要です。理想的ではありません。

ここで、次のテーブル構造を考えます。

 
 + -------------- + + --------------- + + ------ ------- + 
 |事| | thing_attr | | attr | 
 | -------------- | | --------------- | | ------------- | 
 | id | <--- + | thing_id(fk)| +> | id | 
 |タイプ| | attr_id(fk)| +-+ |名前| 
 | desc | |値| | | 
 + -------------- + + --------------- + + ---------- --- + 

あなたはその基本的な分野であなたのものを持っています。さらに2つのテーブルがあります。属性を持つもの。各フィールドはattrテーブルの行です。そしてthing_attrは、thingテーブルとattrテーブルに関連する外部キーのペアを含みます。そして、このエンティティには値フィールドがあり、そのエンティティのフィールドの値が何であっても格納できます。

これで、attrテーブルを実行時に更新でき、アプリケーション全体に大きな影響を与えることなく、新しいフィールドをその場で追加(または削除)できる構造になりました。

クエリは少し複雑になり、検証も複雑になります(ファンキーなストアドプロシージャまたはすべてのクライアント側)。そのトレードオフです。

いつかマイグレーションを行う必要があり、アプリケーションに戻って、最初に配布したスキーマよりも6ダースほど多い属性があることに気付いた場合も検討してください。これにより、エンティティ属性値テーブルを正しく使用するとクリーンになる可能性がある、醜い移行とアップグレードが可能になります。 (常にではありませんが、可能です。)


実行時にスキーマを変更するだけの欠点はありますか?ユーザーが物事に新しい属性が必要だと思った場合、テーブルに列を動的に追加するだけですか?

Nosqlデータベースの適切なフレーバーを使用している場合は、おそらくこれを実行できます(このためのnosqlの適切なフレーバーはおそらく---(key-value store であり、これはEAVです)上記のリレーショナルテーブルの表)。 ただし他の場所で詳細に説明されているnosqlのすべての妥協点が付属しています。

代わりにリレーショナルデータベースで作業している場合は、スキーマが必要です。列を動的に追加するということは、以下のサブセットが当てはまることを意味します。

  • あなたはメタデータベースプログラミングを行っています。 Nice ORMを使用してこの列をそのフィールドにきれいにマッピングできる代わりに、おそらくselect *次に、データが実際に何であるかを確認するためにいくつかの複雑なコードを実行し( JavaのResultSetMetaData を参照)、それをマップ(または他のデータ型-ただしに格納しない) コード内の素晴らしいフィールド)。これにより、従来のアプローチで使用していたタイプとタイプミスの安全性がかなり失われます。
  • ORMを放棄した可能性があります。これは、システムに作業を任せる代わりに、すべてのコードに対して生のSQLを記述していることを意味します。
  • クリーンアップグレードをあきらめました。顧客が次のバージョンでも使用する1つの名前のフィールドを追加するとどうなりますか?マッチメイキングサイトでは、タイムスタンプを保存するためのhasdateフィールドを追加しようとするアップグレードは、hasdateとして既に定義されています。
  • クエリを壊す予約語を使用して、顧客がシステムを壊さないことを信頼しています...どこかで。
  • あなたは1つのデータベースブランドに縛られています。異なるデータベースの [〜#〜] ddl [〜#〜] は異なります。データベースタイプは、この最も簡単な例です。 varchar2 vs textなど。列を追加するコードはMySQLでは機能しますが、Postgres、Oracle、SQL Serverでは機能しません。
  • 実際にデータを追加することを顧客に信頼していますかwell?確かに、EAVは理想からはほど遠いですが、開発者が追加しなかった恐ろしいあいまいなテーブル名があり、間違ったタイプのインデックス(ある場合)があり、必要なコードに制約が追加されていません。などなど。
  • アプリケーションを実行しているユーザーにスキーマ変更権限を付与しました。 リトルボビードロップテーブル は、DDLではなくSQLに制限されている場合は不可能です(delete * from students代わりに、実際にデータベースを台無しにすることはできません)。事故や悪意のある活動からのスキーマアクセスで問題が発生する可能性のあるものの数は急増しています。

これは、結局のところ「やらない」ということです。これが本当に必要な場合は、EAVテーブル構造の既知のパターン、またはこの構造専用のデータベースを使用してください。テーブルに任意のフィールドを作成させないでください。頭痛はそれだけの価値はありません。

19
user40980

これをうまく行うのは難しいです。

もちろん、計画しているような1回限りのアプリケーションの場合は、各フィールドに列を追加するだけで、トレーニングを受けていないユーザーがSQLコマンドラインを使用するよりも安全にフィールドを定義できるUIを提供できます。あるいは、恐ろしい Entity-Attribute-Value パターンに従うこともできます。これは、この種の問題に対する古典的な応答であり、多少恐ろしいものです。 EAVフィールドを定義するためのUIの構築は通常、データベース列の場合よりもはるかに複雑であり、クエリはかなり複雑になる可能性がありますが、多数のフィールド(ieの場合、非常にまばらマトリックススキーマ)、それは仕事を成し遂げる唯一の方法かもしれません。

5
Ross Patterson

最近似たようなことをクロスしてきました。

2つのテーブルを作りました。

1: table Objects 
    Id , name, type

彼はすべてあなたのオブジェクトです。それの名前を設定します。

そして、このオブジェクトのタイプ:-私にとって利用可能なタイプは、inventory、inventory_item、officeでした。

通常の設定では、n個のアイテムが子またはインベントリであり、これもオフィスの子であり、結合テーブルを使用してオブジェクトを相互に結合しました。

2 table settings 
     organization_Id , title, value , type

設定テーブルには、その特定のオブジェクトタイプのすべてのフィールド名と値の値が含まれています。

オフィスの特性例

場所、電話、勤務時間

そしてアイテム

  • 価格
  • Barcode

など、これらすべてのプロパティはモデルによって適用され、個別の行として設定テーブルに保存されます(ただし、同じフィールドに複数の行が表示されないようにするには、置換ではなく挿入を使用してください)

したがって、オフィスが必要なときはいつでも、すべての関係と設定を簡単にロードできます。

その後、設定からすべての行をピボットし、それだけです。

また、設定を在庫(グローバルではなく)のアイテムに固有にする場合は、object_I'd = object_objects Relations tableから設定し、settings.type = relation_settingを設定します。

私がラップトップにたどり着いたときに答えを再フォーマットしようとする意味を理解していただければ幸いです

0
Zalaboza

ユーザー定義フィールドを許可することは悪い習慣ですか?

いいえ、それは悪い習慣ではありません。それはかなり一般的です。 OO用語では、これは継承と呼ばれます。基本クラスのinventoryItemと2つの継承クラスAudioCDと家具があります。

しかし一般的に言えば、人々はこのようなものを「現実の生活」でどのように扱うのでしょうか?

あなたは、inventoryItem、AudioCD、および家具をデータベースに保存する方法を決定する必要があります。

Easy-queryがあなたにとって最も重要であり、db-space/normalizationが問題ではない場合、 "table-per-hierarchy"スキーマを実装します。

スペース/正規化が最も重要で、より複雑なクエリが問題にならない場合は、「type-per-type」スキーマを実装します。

詳細については、 dotnet table-per-type-vs-table-per-hierarchy-inheritance または Java hibernate inheritance を参照してください。

0
k3b