バグトラッカー、顧客リソース管理、および同様のビジネスツールでよく見られる「ユーザー定義フィールド」に到達し始めると、それらは無数のフィールドを持つテーブルに裏付けられていないということです(ある場合は、それ自身)。
代わりに、エンティティ属性値テーブルの設計と、有効な属性を管理する関連管理ツールがあります。
次の表を考慮してください。
+ -------------- +
| こと|
| -------------- |
| id |
| タイプ|
| desc |
| attr1 |
| attr2 |
| attr3 |
| attr4 |
| attr5 |
+ -------------- +
これは、いくつかの属性を追加した後です。代わりにattr1
、それは読みふりartist
またはtracks
またはgenre
または持っているものを何でも属性。そして、5の代わりに、50だったらどうなるでしょう。明らかに、それは管理不能です。また、新しいフィールドを処理するには、モデルの更新とアプリケーションの再デプロイメントが必要です。理想的ではありません。
ここで、次のテーブル構造を検討します。
+ -------------- + + --------------- + + ------------- +
| こと| | thing_attr | | attr |
| -------------- | | --------------- | | ------------- |
| id | <--- + | thing_id(fk)| +> | id |
| タイプ| | attr_id(fk)| +-+ | 名前|
| desc | | 値| | |
+ -------------- + + --------------- + + ------------- +
基本的なフィールドがあります。さらに2つのテーブルがあります。属性を持つもの。各フィールドはattr
テーブル内の行です。そしてthing_attr
、thing
テーブルとテーブルに関連する外部キーのペアがありattr
ます。そして、これには値フィールドがあり、そのエンティティのフィールドの値が何であれ格納します。
また、実行時にattrテーブルを更新し、アプリケーション全体に大きな影響を与えることなく、新しいフィールドをその場で追加(または削除)できる構造ができました。
クエリは少し複雑で、検証も複雑になります(ファンキーなストアドプロシージャまたはすべてのクライアント側)。デザインのトレードオフ。
また、いつか移行を行う必要があり、アプリケーションに戻って、最初に配布したスキーマよりも半ダース以上の属性があることに気づいた場合も考えてください。これにより、エンティティ属性値テーブルが正しく使用された場合にクリーンになる可能性のあるい移行とアップグレードが行われます。(常にではありませんが、可能です。)
実行時にスキーマを変更するだけの欠点はありますか?ユーザーが何かに新しい属性が必要だと思う場合、動的にテーブルに列を追加しますか?
適切なフレーバーのnosqlデータベースを使用している場合は、おそらくこれを行うことができます(これに適したnosqlのフレーバーは、おそらく、上記のリレーショナルデータベースのEAVテーブルであるキーと値のストアです)面倒なし。 ただし、他の場所で詳細に説明されているnosqlのすべての妥協点があります。
代わりにリレーショナルデータベースで作業している場合は、スキーマが必要です。列を動的に追加するということは、次のことの一部が当てはまることを意味します。
- メタデータベースプログラミングを行っています。素敵なORMでこの列をそのフィールドにきれいにマップできる代わりに、おそらく次のような
select *
ことをしてから、実際にデータが何であるかを調べるためにいくつかの複雑なコードを実行し(JavaのResultSetMetaDataを参照)、それをマップに保存します(または他のデータ型-しかし、コード内の素晴らしいフィールドではありません)。これにより、従来のアプローチで持っていたタイプとタイプの安全性がかなり失われます。
- ORMを放棄した可能性があります。これは、システムに作業を任せる代わりに、すべてのコードに対して生のSQLを作成していることを意味します。
- クリーンアップグレードの実行をあきらめました。顧客が、次のバージョンでも使用する1つの名前のフィールドを追加するとどうなりますか?マッチメイキングサイトでは
hasdate
、タイムスタンプを保存するためのフィールドを追加するアップグレードは、マッチをhasdate
成功させるためのブール値として既に定義されており、アップグレードが中断します。
- クエリを中断する予約語を使用して、顧客がシステムを壊さないことを信頼しています...どこかで。
- 1つのデータベースブランドに縛られています。異なるデータベースのDDLは異なります。データベースタイプは、この最も簡単な例です。
varchar2
vs text
など。列を追加するコードはMySQLで機能しますが、Postgres、Oracle、またはSQL Serverでは機能しません。
- 実際にデータを適切に追加することを顧客に信頼していますか?確かに、EAVは理想からはほど遠いですが、開発者が追加しなかったいくつかの恐ろしい不明瞭なテーブル名があり、間違ったタイプのインデックス(もしあれば)があり、必要なコードに制約が追加されていませんなどなど。
- アプリケーションを実行しているユーザーにスキーマ変更権限を付与しました。Little Bobby Drop Tablesは、DDLではなくSQLに制限されている場合は使用できません(
delete * from students
代わりに使用できることを確認してください。ただし、実際にはデータベースを不適切な方法で台無しにすることはできません)。事故または悪意のあるアクティビティのいずれかによるスキーマアクセスで問題が発生する可能性のある数は急増しています。
これは本当に「やらないで」ということになります。これが本当に必要な場合は、EAVテーブル構造の既知のパターン、またはこの構造専用のデータベースを使用してください。テーブルに任意のフィールドを作成させないでください。頭痛はそれだけの価値はありません。