web-dev-qa-db-ja.com

動的データベーススキーマ

動的論理データベーススキーマにストレージを提供するための推奨アーキテクチャは何ですか?

明確にするために:システムが生産中にユーザーによってスキーマが拡張または変更されるモデルのストレージを提供する必要がある場合、これを可能にする優れたテクノロジー、データベースモデルまたはストレージエンジンは何ですか?

説明するいくつかの可能性:

  • 動的に生成されたDMLを介したデータベースオブジェクトの作成/変更
  • 多数の疎な物理列を持つテーブルを作成し、「オーバーレイ」論理スキーマに必要なものだけを使用する
  • 動的な列値を行として格納する「長くて狭い」テーブルを作成し、特定のエンティティのすべての値を含む「短くて広い」行セットを作成するためにピボットする必要がある
  • BigTable/SimpleDB PropertyBag型システムの使用

実世界での経験に基づいた回答は大歓迎です

65
Fake Jim

あなたが提案しているものは新しいものではありません。多くの人が試してみました...ほとんどの人が「無限の」柔軟性を追い求め、代わりにそれよりもはるかに少ないことに気づきました。これは、データベース設計の「ゴキブリモーテル」です。データは入りますが、それを取り出すことはほとんど不可能です。あらゆる種類の制約に対するコードの記述を試みて概念化すると、私が何を意味するかがわかります。

最終的な結果は、通常、デバッグ、保守が非常に難しく、データの一貫性の問題に満ちたシステムです。これは常にのケースではありませんが、多くの場合、それが最終的な方法です。ほとんどの場合、プログラマはこの列車の残骸が来るのを見ていないので、それに対して防御的にコーディングすることに失敗します。また、多くの場合、「無限の」柔軟性は本当に必要ではないというケースになります。開発チームが「ここにどんな種類のデータを置くのかわからないので、何を入れてもいい」という仕様を取得したとき、それは非常に悪い「臭い」です...そしてエンドユーザーは大丈夫です使用できる事前定義された属性タイプを持つ(汎用電話番号をコーディングし、それらの任意の番号を作成できるようにする-これは適切に正規化されたシステムでは簡単で、柔軟性と整合性を維持します!)

非常に優れた開発チームがあり、この設計で克服しなければならない問題をよく知っている場合、うまくコードを作成できます設計された、ひどくバグのあるシステムではありません。ほとんどの時間。

しかし、なぜあなたに反対するオッズが多いのでしょうか?

信じられない? 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

36
Matt Rogish

MSSQLで厳密に型指定されたxmlフィールドが機能しました。

20
Bloodhound

他の人が言ったように、他に選択肢がない限りこれをしないでください。これが必要なケースの1つは、ユーザーがカスタムデータを記録できる市販の製品を販売している場合です。私の会社の製品はこのカテゴリーに分類されます。

顧客にこれを許可する必要がある場合、いくつかのヒントを次に示します。
-スキーマの変更を実行するrobust管理ツールを作成し、これらの変更を他の方法で許可しないでください。
-管理機能にします。通常のユーザーによるアクセスを許可しないでください。
-すべてのスキーマ変更に関するすべての詳細を記録します。これは、問題のデバッグに役立ちます。また、顧客が何か愚かなことをした場合にもCYAデータを提供します。

これらのこと(特に最初のもの)をうまく行うことができれば、あなたが言及したどのアーキテクチャでも機能します。私の好みは、データベースオブジェクトを動的に変更することです。これにより、カスタムフィールドに格納されているデータにアクセスするときに、DBMSのクエリ機能を利用できるようになります。他の3つのオプションでは、大量のデータをロードしてから、ほとんどのデータ処理をコードで実行する必要があります。

16
Josh Yeager

同様の要件があり、スキーマレス MongoDB を使用することにしました。

MongoDB(「巨大な」から)は、C++プログラミング言語で書かれた、オープンソース、スケーラブル、高性能、スキーマフリー、ドキュメント指向のデータベースです。 (ウィキペディア)

ハイライト:

  • 豊富なクエリ機能があります(SQL DBに最も近いかもしれません)
  • 生産準備完了(foursquare、sourceforgeで使用)

Lowdarks(理解する必要があるので、mongoを正しく使用できます):

9
clyfe

私はそれを実際のプロジェクトでやった:

データベースは、50の配列である1つのフィールドを持つ1つのテーブルで構成されていました。「Word」インデックスが設定されていました。すべてのデータには型がないため、「Wordインデックス」は期待どおりに機能しました。数値フィールドは文字として表され、実際のソートはクライアント側で行われました。 (必要に応じて、データ型ごとに複数の配列フィールドを使用することも可能です)。

論理テーブルの論理データスキーマは、異なるテーブル行 'type'(最初の配列要素)を持つ同じデータベース内に保持されていました。また、同じ「タイプ」フィールドを使用したコピーオンライトスタイルでの単純なバージョン管理もサポートしていました。

利点:

  1. データベースをダンプ/リロードする必要なく、動的に列を再配置および追加/削除できます。新しい列データは、ゼロ時間で(実質的に)初期値に設定できます。
  2. すべてのレコードとテーブルが同じサイズであるため、断片化は最小限に抑えられ、パフォーマンスが向上する場合があります。
  3. すべてのテーブルスキーマは仮想です。任意の論理スキーマ構造が可能です(再帰的、またはオブジェクト指向でも)。
  4. 「一度だけ書き込み、ほとんど読み取り、削除なし/削除済みとしてマークする」データに適しています(実際、ほとんどのWebアプリはそのようなものです)。

短所:

  1. 略語ではなく、完全な単語のみによるインデックス作成、
  2. 複雑なクエリも可能ですが、パフォーマンスはわずかに低下します。
  3. 使用するデータベースシステムが配列とWordインデックスをサポートしているかどうかによって異なります(PROGRESS RDBMSで実装されました)。
  4. リレーショナルモデルは、プログラマーの頭の中にしかありません(つまり、実行時のみ)。

そして今、私は次のステップができると考えています-ファイルシステムレベルでそのようなデータベースを実装すること。それは比較的簡単かもしれません。

7
Thevs

リレーショナルDBを持つことの全体的なポイントは、データの安全性と一貫性を保つことです。ユーザーがスキーマを変更できるようにすると、データの整合性が保たれます...

CMSシナリオのように、異種データを保存する必要がある場合は、XSDによって検証されたXMLを連続して保存することをお勧めします。もちろん、パフォーマンスと簡単な検索機能を失いますが、それは私見とのトレードオフです。

2016年なので、XMLを忘れてください! JSONを使用して、適切に型指定された列をバックエンドとして、非リレーショナルデータバッグを格納します。通常、値バッグ内でクエリする必要はありません。これは、多くの現代のSQLデータベースがJSONをネイティブに理解していても遅くなります。

6
Sklivvz

2つのデータベースを作成する

  • DB1には静的テーブルが含まれており、データの「実際の」状態を表します。
  • DB2は、ユーザーが自由に処理できます。ユーザー(またはユーザー)は、DB1から奇妙な形のテーブルを作成するコードを記述する必要があります。
3
AJ.

本当に欲しいのは、実際のデータを保存するための柔軟なスキーマを記述することができるデータベーススキーマである、ある種の「メタスキーマ」です。動的なスキーマの変更は扱いにくいものであり、特にユーザーが変更を許可されている場合を除いて、やりたいことではありません。

他のどのデータベースよりもこのタスクに適したデータベースを見つけることはできないため、最善の策は他の基準に基づいてデータベースを選択することです。たとえば、DBをホストするためにどのプラットフォームを使用していますか?アプリは何語で書かれていますか?等

「メタスキーマ」の意味を明確にするには:

CREATE TABLE data (
    id INTEGER NOT NULL AUTO_INCREMENT,
    key VARCHAR(255),
    data TEXT,

    PRIMARY KEY (id)
);

これは非常に単純な例です。ニーズに合った何かを持っている可能性があります(そして、できれば少し簡単に作業できます)が、それは私のポイントを説明するのに役立ちます。データベーススキーマ自体は、アプリケーションレベルで不変であると見なす必要があります。構造の変更はすべてデータに反映される必要があります(つまり、そのスキーマのインスタンス化)。

3
Daniel Spiewak

質問に示されているモデルは、生産システム全体で使用されていることを知っています。かなり大きいものは、私が働いている大規模な大学/教育機関で使用されています。彼らは特に、多くのさまざまなデータ収集システムによって収集されたデータをマッピングするために、ロングナローテーブルアプローチを使用しています。

また、Googleは最近、内部のデータ共有プロトコルであるプロトコルバッファを、コードサイトを介してオープンソースとしてリリースしました。このアプローチをモデルにしたデータベースシステムは非常に興味深いものです。

以下を確認してください。

エンティティ属性値モデル

Googleプロトコルバッファー

3
siculars

EAVアプローチは最善のアプローチだと思いますが、コストがかかります

2
kamal

ウィキペディアには、問題空間の優れた概要があります。

http://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model

2
DenNukem

古いトピックであることは知っていますが、現実を失うことはないと思います。私は今そのようなものを開発しています。これが私のアプローチです。アプリケーションフレームワークとしてMySQL、Apache、PHP、およびZend Framework 2でサーバー設定を使用しますが、他の設定でも同様に機能するはずです。

ここに簡単な実装ガイドがあります。これからさらに自分で進化させることができます。

効果的なSQLは複雑すぎるため、独自のクエリ言語インタープリターを実装する必要があります。

例:

select id, password from user where email_address = "[email protected]"

物理データベースのレイアウト:

テーブル「仕様」:(データアクセスレイヤーにキャッシュする必要があります)

  • id:int
  • parent_id:int
  • 名前:varchar(255)

テーブル「アイテム」:

  • id:int
  • parent_id:int
  • spec_id:int
  • データ:varchar(20000)

テーブル 'specs'の内容:

  • 1、0、「ユーザー」
  • 2、1、「email_address」
  • 3、1、「パスワード」

テーブル「アイテム」の内容:

独自のクエリ言語での例の翻訳:

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]"
            )
    )

あなたがそのアイデアを得て、そのアプローチがあなたにとって実行可能かどうかを自分で判断できることを願っています。

楽しい! :-)

2
Oliver Konig

過去にオプションCを選択しました- 動的な列の値を行として格納する「長くて狭い」テーブルを作成し、特定のエンティティのすべての値を含む「短くて広い」行セットを作成するためにピボットする必要があります。。しかし、私はORMを使用していましたが、それは本当に物事を苦しくさせました。たとえば、LinqToSqlでどのように実行するかは考えられません。フィールドを参照するには、ハッシュテーブルを作成する必要があると思います。

@Skliwz:彼はユーザーがユーザー定義フィールドを作成できるようにすることにもっと興味があると思う。

0
Danimal

C2.com wikiで、「Dynamic Relational」の概念が検討されました。 DBAは不要です。列とテーブルは作成時書き込みです。制約を追加して従来のRDBMSのように動作させる場合を除きます。プロジェクトが成熟するにつれて、徐々に「ロックダウン」できます。

概念的には、各行をXMLステートメントと考えることができます。たとえば、従業員レコードは次のように表すことができます。

<employee lastname="Li" firstname="Joe" salary="120000" id="318"/>

これは、notではなく、XMLとして実装する必要があることを意味します。これは単なる便利な概念化です。 「SELECT madeUpColumn ...」などの存在しない列を要求した場合、空白またはnullとして扱われます(追加された制約で禁止されていない限り)。 [〜#〜] sql [〜#〜]を使用することもできますが、暗黙の型モデルのために比較に注意する必要があります。しかし、ダイナミックリレーショナルシステムのユーザーは、型の処理以外に、既存のRDBMSの知識のほとんどを活用できるため、自宅にいるように感じるでしょう。今、誰かがそれを構築するだけなら...

0
FloverOwe

ElasticSearch。特に、日付ごとにパーティション分割できるデータセットを扱っている場合、データにJSONを使用でき、SQLを使用してデータを取得することは固定されていない場合は、これを考慮する必要があります。

ESは、送信する新しいJSONフィールドのスキーマを、自動的に、ヒントを使用して、または手動で1つのHTTPコマンドで定義/変更できる(「マッピング」)推論します。 SQLをサポートしていませんが、いくつかの優れたルックアップ機能、さらには集約を備えています。

0
Oren