動的論理データベーススキーマにストレージを提供するための推奨アーキテクチャは何ですか?
明確にするために:システムが生産中にユーザーによってスキーマが拡張または変更されるモデルのストレージを提供する必要がある場合、これを可能にする優れたテクノロジー、データベースモデルまたはストレージエンジンは何ですか?
説明するいくつかの可能性:
実世界での経験に基づいた回答は大歓迎です
あなたが提案しているものは新しいものではありません。多くの人が試してみました...ほとんどの人が「無限の」柔軟性を追い求め、代わりにそれよりもはるかに少ないことに気づきました。これは、データベース設計の「ゴキブリモーテル」です。データは入りますが、それを取り出すことはほとんど不可能です。あらゆる種類の制約に対するコードの記述を試みて概念化すると、私が何を意味するかがわかります。
最終的な結果は、通常、デバッグ、保守が非常に難しく、データの一貫性の問題に満ちたシステムです。これは常にのケースではありませんが、多くの場合、それが最終的な方法です。ほとんどの場合、プログラマはこの列車の残骸が来るのを見ていないので、それに対して防御的にコーディングすることに失敗します。また、多くの場合、「無限の」柔軟性は本当に必要ではないというケースになります。開発チームが「ここにどんな種類のデータを置くのかわからないので、何を入れてもいい」という仕様を取得したとき、それは非常に悪い「臭い」です...そしてエンドユーザーは大丈夫です使用できる事前定義された属性タイプを持つ(汎用電話番号をコーディングし、それらの任意の番号を作成できるようにする-これは適切に正規化されたシステムでは簡単で、柔軟性と整合性を維持します!)
非常に優れた開発チームがあり、この設計で克服しなければならない問題をよく知っている場合、うまくコードを作成できます設計された、ひどくバグのあるシステムではありません。ほとんどの時間。
しかし、なぜあなたに反対するオッズが多いのでしょうか?
信じられない? Google「One True Lookup Table」または「single table design」。いくつかの良い結果: http://asktom.Oracle.com/pls/asktom/f?p=100:11:0:::::P11_QUESTION_ID:10678084117056
http://thedailywtf.com/Comments/Tom_Kyte_on_The_Ultimate_Extensibility.aspx?pg=
http://www.dbazine.com/ofinterest/oi-articles/celko22
http://thedailywtf.com/Comments/The_Inner-Platform_Effect.aspx?pg=2
MSSQLで厳密に型指定されたxmlフィールドが機能しました。
他の人が言ったように、他に選択肢がない限りこれをしないでください。これが必要なケースの1つは、ユーザーがカスタムデータを記録できる市販の製品を販売している場合です。私の会社の製品はこのカテゴリーに分類されます。
顧客にこれを許可する必要がある場合、いくつかのヒントを次に示します。
-スキーマの変更を実行するrobust管理ツールを作成し、これらの変更を他の方法で許可しないでください。
-管理機能にします。通常のユーザーによるアクセスを許可しないでください。
-すべてのスキーマ変更に関するすべての詳細を記録します。これは、問題のデバッグに役立ちます。また、顧客が何か愚かなことをした場合にもCYAデータを提供します。
これらのこと(特に最初のもの)をうまく行うことができれば、あなたが言及したどのアーキテクチャでも機能します。私の好みは、データベースオブジェクトを動的に変更することです。これにより、カスタムフィールドに格納されているデータにアクセスするときに、DBMSのクエリ機能を利用できるようになります。他の3つのオプションでは、大量のデータをロードしてから、ほとんどのデータ処理をコードで実行する必要があります。
同様の要件があり、スキーマレス MongoDB を使用することにしました。
MongoDB(「巨大な」から)は、C++プログラミング言語で書かれた、オープンソース、スケーラブル、高性能、スキーマフリー、ドキュメント指向のデータベースです。 (ウィキペディア)
ハイライト:
Lowdarks(理解する必要があるので、mongoを正しく使用できます):
私はそれを実際のプロジェクトでやった:
データベースは、50の配列である1つのフィールドを持つ1つのテーブルで構成されていました。「Word」インデックスが設定されていました。すべてのデータには型がないため、「Wordインデックス」は期待どおりに機能しました。数値フィールドは文字として表され、実際のソートはクライアント側で行われました。 (必要に応じて、データ型ごとに複数の配列フィールドを使用することも可能です)。
論理テーブルの論理データスキーマは、異なるテーブル行 'type'(最初の配列要素)を持つ同じデータベース内に保持されていました。また、同じ「タイプ」フィールドを使用したコピーオンライトスタイルでの単純なバージョン管理もサポートしていました。
利点:
短所:
そして今、私は次のステップができると考えています-ファイルシステムレベルでそのようなデータベースを実装すること。それは比較的簡単かもしれません。
リレーショナルDBを持つことの全体的なポイントは、データの安全性と一貫性を保つことです。ユーザーがスキーマを変更できるようにすると、データの整合性が保たれます...
CMSシナリオのように、異種データを保存する必要がある場合は、XSDによって検証されたXMLを連続して保存することをお勧めします。もちろん、パフォーマンスと簡単な検索機能を失いますが、それは私見とのトレードオフです。
2016年なので、XMLを忘れてください! JSONを使用して、適切に型指定された列をバックエンドとして、非リレーショナルデータバッグを格納します。通常、値バッグ内でクエリする必要はありません。これは、多くの現代のSQLデータベースがJSONをネイティブに理解していても遅くなります。
本当に欲しいのは、実際のデータを保存するための柔軟なスキーマを記述することができるデータベーススキーマである、ある種の「メタスキーマ」です。動的なスキーマの変更は扱いにくいものであり、特にユーザーが変更を許可されている場合を除いて、やりたいことではありません。
他のどのデータベースよりもこのタスクに適したデータベースを見つけることはできないため、最善の策は他の基準に基づいてデータベースを選択することです。たとえば、DBをホストするためにどのプラットフォームを使用していますか?アプリは何語で書かれていますか?等
「メタスキーマ」の意味を明確にするには:
CREATE TABLE data (
id INTEGER NOT NULL AUTO_INCREMENT,
key VARCHAR(255),
data TEXT,
PRIMARY KEY (id)
);
これは非常に単純な例です。ニーズに合った何かを持っている可能性があります(そして、できれば少し簡単に作業できます)が、それは私のポイントを説明するのに役立ちます。データベーススキーマ自体は、アプリケーションレベルで不変であると見なす必要があります。構造の変更はすべてデータに反映される必要があります(つまり、そのスキーマのインスタンス化)。
質問に示されているモデルは、生産システム全体で使用されていることを知っています。かなり大きいものは、私が働いている大規模な大学/教育機関で使用されています。彼らは特に、多くのさまざまなデータ収集システムによって収集されたデータをマッピングするために、ロングナローテーブルアプローチを使用しています。
また、Googleは最近、内部のデータ共有プロトコルであるプロトコルバッファを、コードサイトを介してオープンソースとしてリリースしました。このアプローチをモデルにしたデータベースシステムは非常に興味深いものです。
以下を確認してください。
EAVアプローチは最善のアプローチだと思いますが、コストがかかります
ウィキペディアには、問題空間の優れた概要があります。
http://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model
古いトピックであることは知っていますが、現実を失うことはないと思います。私は今そのようなものを開発しています。これが私のアプローチです。アプリケーションフレームワークとしてMySQL、Apache、PHP、およびZend Framework 2でサーバー設定を使用しますが、他の設定でも同様に機能するはずです。
ここに簡単な実装ガイドがあります。これからさらに自分で進化させることができます。
効果的なSQLは複雑すぎるため、独自のクエリ言語インタープリターを実装する必要があります。
例:
select id, password from user where email_address = "[email protected]"
物理データベースのレイアウト:
テーブル「仕様」:(データアクセスレイヤーにキャッシュする必要があります)
テーブル「アイテム」:
テーブル 'specs'の内容:
テーブル「アイテム」の内容:
独自のクエリ言語での例の翻訳:
select id, password from user where email_address = "[email protected]"
標準SQLの場合は次のようになります。
select
parent_id, -- user id
data -- password
from
items
where
spec_id = 3 -- make sure this is a 'password' item
and
parent_id in
( -- get the 'user' item to which this 'password' item belongs
select
id
from
items
where
spec_id = 1 -- make sure this is a 'user' item
and
id in
( -- fetch all item id's with the desired 'email_address' child item
select
parent_id -- id of the parent item of the 'email_address' item
from
items
where
spec_id = 2 -- make sure this is a 'email_address' item
and
data = "[email protected]" -- with the desired data value
)
)
スペック名からspec_idを取得するには、スペックテーブルを連想配列またはハッシュテーブルなどにキャッシュする必要があります。そうでない場合は、次のスニペットのように、名前からspec_idを取得するために、さらにSQLオーバーヘッドを挿入する必要があります。
悪い例、これを使用しないでください、これを避けて、代わりにスペック表をキャッシュしてください!
select
parent_id,
data
from
items
where
spec_id = (select id from specs where name = "password")
and
parent_id in (
select
id
from
items
where
spec_id = (select id from specs where name = "user")
and
id in (
select
parent_id
from
items
where
spec_id = (select id from specs where name = "email_address")
and
data = "[email protected]"
)
)
あなたがそのアイデアを得て、そのアプローチがあなたにとって実行可能かどうかを自分で判断できることを願っています。
楽しい! :-)
過去にオプションCを選択しました- 動的な列の値を行として格納する「長くて狭い」テーブルを作成し、特定のエンティティのすべての値を含む「短くて広い」行セットを作成するためにピボットする必要があります。。しかし、私はORMを使用していましたが、それは本当に物事を苦しくさせました。たとえば、LinqToSqlでどのように実行するかは考えられません。フィールドを参照するには、ハッシュテーブルを作成する必要があると思います。
@Skliwz:彼はユーザーがユーザー定義フィールドを作成できるようにすることにもっと興味があると思う。
C2.com wikiで、「Dynamic Relational」の概念が検討されました。 DBAは不要です。列とテーブルは作成時書き込みです。制約を追加して従来のRDBMSのように動作させる場合を除きます。プロジェクトが成熟するにつれて、徐々に「ロックダウン」できます。
概念的には、各行をXMLステートメントと考えることができます。たとえば、従業員レコードは次のように表すことができます。
<employee lastname="Li" firstname="Joe" salary="120000" id="318"/>
これは、notではなく、XMLとして実装する必要があることを意味します。これは単なる便利な概念化です。 「SELECT madeUpColumn ...」などの存在しない列を要求した場合、空白またはnullとして扱われます(追加された制約で禁止されていない限り)。 [〜#〜] sql [〜#〜]を使用することもできますが、暗黙の型モデルのために比較に注意する必要があります。しかし、ダイナミックリレーショナルシステムのユーザーは、型の処理以外に、既存のRDBMSの知識のほとんどを活用できるため、自宅にいるように感じるでしょう。今、誰かがそれを構築するだけなら...
ElasticSearch。特に、日付ごとにパーティション分割できるデータセットを扱っている場合、データにJSONを使用でき、SQLを使用してデータを取得することは固定されていない場合は、これを考慮する必要があります。
ESは、送信する新しいJSONフィールドのスキーマを、自動的に、ヒントを使用して、または手動で1つのHTTPコマンドで定義/変更できる(「マッピング」)推論します。 SQLをサポートしていませんが、いくつかの優れたルックアップ機能、さらには集約を備えています。