私の現在のプロジェクトは、基本的に工場文書管理システムの実行です。
とはいえ、いくつかのしわ(驚き、驚き)があります。いくつかのしわはプロジェクトにかなり固有のものですが、標準的な答えを持たない(とにかく見つけることができる)一般的な観察と質問がいくつかあり、それはより広い問題領域に適用できると思います。ここにはたくさんあり、StackExchangeのQ&A形式に適しているかどうかはわかりませんが、a)答えられる質問であり、b)コミュニティに役立つほど具体的でないと思います。私の考慮事項のいくつかは私に固有のものですが、この質問は、SQLとNoSQLとその両方を決定することに直面している人にとって役に立つと思います。
背景:
作成しているWebアプリには、本質的に明らかにリレーショナルなデータと、ドキュメント指向のデータが含まれています。ケーキを持って食べたいです。
TL; DR:以下の#5は匂いテストに合格すると思います。あなたは?単一のアプリケーションでSQLとNOSQLをこのように統合した経験はありますか?このクラスの問題に対するすべての可能なアプローチを以下にリストしようとしました。有望な代替案を見逃していませんか?
複雑さ:
- 文書には多くの異なるクラスがあります。要件はすでに何十もの異なる文書を要求しています。この数は増えるだけです。可能な限り最良のケースは、ドメイン専門家がDBAやプログラマの介入なしに新しいドキュメントクラスの追加を処理できるように、単純なドメイン固有の言語、コード生成、および柔軟なスキーマを活用できるケースです。(注:Greenspunの第10規則を順守していることを既に認識しています)
- 以前の正常な書き込みの整合性は、プロジェクトの中心的な要件です。データはビジネスに不可欠です。書き込みに関するACIDの完全なセマンティクスは、正常に書き込まれたものが書き込まれたままであれば、犠牲になる可能性があります。
- 文書自体は複雑です。特定のケースのプロトタイプドキュメントでは、ドキュメントインスタンスごとに150以上の個別のデータを保存する必要があります。病理学的症例は1桁悪化する可能性がありますが、確かに2ではありません。
- 単一クラスのドキュメントは、後の時点で更新の対象となる移動ターゲットです。
- Djangoをリレーショナルデータベースにフックすると、無料のものが好きです。django-nonrelフォークを使用するために2つのDjangoバージョンに戻る必要なく、景品を保持したいと思います。1.3にダウングレードするよりも、ORM全体をダンプする方が望ましいです。
本質的には、リレーショナルデータ(ユーザー、グループなどの典型的なWebアプリのもの、および複雑なクエリをリアルタイムで切り刻むことができる必要があるドキュメントメタデータ)とドキュメントデータ(たとえば、参加やクエリに関心のない数百のフィールド-データの唯一のユースケースは、入力された単一のドキュメントを表示することです。
私は私の好みの方法で健全性チェック(あなたが私の投稿履歴をチェックする場合、私はDBAではないという事実についてかなり明確です)を行い、他の解決のために出会ったすべてのオプションを列挙したかったですリレーショナルデータと非リレーショナルデータの両方を含む、ほぼ同様の問題。
提案されたソリューション:
1.ドキュメントクラスごとに1つのテーブル
各ドキュメントクラスは、すべてのメタデータとデータの列を持つ独自のテーブルを取得します。
利点:
- 標準のSQLデータモデルが使用されています。
- リレーショナルデータは可能な限り最適な方法で処理されます。必要に応じて後で非正規化します。
- Djangoのビルトイン管理インターフェイスはこれらのテーブルを内省することに慣れており、ORMは100%のデータをそのまま使用できます。
短所:
- メンテナンスの悪夢。数千(数十?)の列を持つ数十(数百?)のテーブル。
- どのテーブルに書き込むかを正確に決定するアプリケーションレベルのロジック。テーブル名をクエリのパラメータにすることは悪臭を放ちます。
- 基本的に、すべてのビジネスロジックの変更にはスキーマの変更が必要です。
- 病理学的なケースでは、複数のテーブルにまたがる単一のフォームのデータをストライピングする必要があるかもしれません(参照:PostgreSQLテーブルの列の最大数は?)。
- 私たちはおそらく、人生と私たちを憎むことになるであろう本当の、神に正直なDBAを見つけるために行く必要があるでしょう。
2. EAVモデリング
フィールドテーブルのみがあります。エンティティー属性値のモデリングはすでに十分に理解されています。完全を期すために含めました。2013年に開始される新しいプロジェクトは、意図的にEAVアプローチを採用するとは思わない。
利点:
- モデル化が簡単。
短所:
- クエリがより困難です。
- DBレイヤーには、1つのアプリレベルのオブジェクトを構成するものを簡単に表現することはなくなりました。
- DBレベルの制約チェックが失われます。
- 1つのテーブルの行数は、100〜1000倍の速度で増加します。おそらく将来の問題点はパフォーマンス面です。
- 限られたインデックス付けが可能。
- ORMに関する限り、DBスキーマは無意味です。Webアプリのものを含むバッテリーは保持されますが、カスタムデータモデルにはカスタムクエリが必要になります。
3. PostgreSQL hstoreまたはjsonフィールドを使用します
これらのフィールドタイプのいずれかは、リレーショナルDBのコンテキスト内でスキーマレスデータを格納するためのトリックを行います。私はすぐにこの溶液にジャンプしない唯一の理由は、(バージョン8.4それほどではないに導入された比較的新しいですその新しい)、私はそれにゼロ以前のエクスポージャーを持っていると私は疑わしいです。Mongoはドキュメント間の参照を処理できますが、簡単に正規化されたすてきなデータをすべてMongoに投げるのが不安になるのとまったく同じ理由で、間違っていると思います。
利点:
- Django ORMと組み込みの認証およびセッション管理の利点を活用できます。
- すべてが、以前に他のプロジェクトで正常に使用した1つのバックエンドに残ります。
短所:
- 個人的にはこれに関する経験はありません。
- あまり使用されている機能のようには見えません。NOSQLソリューションを検討している人々にはかなり推奨されているように見えますが、選択されているという証拠はあまりありません。これは、私が何かを見逃しているに違いないと思うようにします。
- 格納される値はすべて文字列です。DBレベルの制約チェックを失います。
- hstore内のデータは、ユーザーがドキュメントを特に表示しない限りユーザーに表示されることはありませんが、より標準的な列に格納されるメタデータは表示されます。私たちはメタデータを打ち破り、作成しようとしているかなり大きなhstoreにはパフォーマンス上の欠点が伴うのではないかと心配しています。
4.完全なドキュメント指向を目指します
(MongoDBの意味で)すべてのものを文書化します。タイプの単一のコレクションを作成し、Document
それを1日と呼びます。すべての周辺データ(ユーザーアカウント、グループなどのデータを含む)もmongoに取り込みます。この解決策は明らかにEAVモデリングよりも優れていますが、#3が間違っていると感じたのと同じ理由で、私には間違っていると感じています。
利点:
- データを事前にモデル化する必要はありません。タイプのドキュメントを含む1つのコレクションを作成し、
Document
それを1日呼び出します。 - コレクションが数百万または数十億ものドキュメントにまで拡大する必要がある場合、既知の良好なスケーリング特性。
- JSON形式(BSON)は、開発者にとって直感的です。
- 私が理解しているように(現時点ではあいまいです)、書き込みの懸念レベルに関して偏執的であることにより、単一のインスタンスでも、ハードドライブのクラッシュまであらゆるものが発生した場合に非常に強力なデータ安全性を提供できます。
短所:
- ORMはDjangoトランクの範囲外です。それと一緒にウィンドウを出て行く景品:authフレームワーク、セッションフレームワーク、管理インターフェイス、他の多くのもの。
- mongoの参照機能(複数のクエリが必要)を使用するか、データを非正規化する必要があります。Djangoから得た景品を失うだけでなく、PostgreSQLで当たり前と思っていたJOINなどの景品も失います。
- データの安全性。MongoDBについて読むと、データがどのように増えて失われるかについて、少なくとも1人の人が常に言及しているようです。彼らは特定の出来事を引用することは決してなく、それはただのホグウォッシュであるか、古いデフォルトの火災に関連しているだけで、書き込み懸念を忘れますが、それでも私を心配しています。もちろん、どのような場合でもかなり偏執的なバックアップ戦略を使用します(データが静かに破損した場合、それはもちろん重要ではありません。)
5. PostgreSQLおよびMongoDB
リレーショナルデータはリレーショナルデータベースに格納され、ドキュメントデータはドキュメント指向のデータベースに格納されます。documents
リレーショナルデータベースのテーブルには、インデックスまたはスライスアンドサイコロに必要なすべてのデータと、ドキュメントのフィールドの実際の値をクエリする必要があるときに使用するMongoDB ObjectIdが含まれています。ドキュメント自体の値にORMまたはビルトイン管理を使用することはできませんが、アプリ全体が基本的にドキュメントの管理インターフェイスであるため、それほど大きな損失ではありません。 ORMの特定の部分を許容できない程度にカスタマイズして、必要な方法で機能するようにします。
利点:
- 各バックエンドは、得意なことだけを行います。
- モデル間の参照は、複数のクエリを必要とせずに保持されます。
- ユーザー、セッションなどに関する限り、Djangoから提供されたバッテリーを保持することができます。
documents
いくつの異なるクラスのドキュメントが作成されても、必要なテーブルは1つだけです。- あまり頻繁に照会されないドキュメントデータは、はるかに頻繁に照会されるメタデータから強く分離されます。
短所:
- ドキュメントデータを取得するには、最初にSQL DBに対して、次にMongoDBに対して2つの順次クエリが必要です(ただし、これは同じデータがMongoに格納され、非正規化されていない場合よりも悪くはありません)
- 書き込みはアトミックではなくなります。単一のMongoドキュメントに対する書き込みはアトミックであることが保証されており、PGは明らかにアトミック性を保証できますが、両方の書き込みのアトミック性を保証するには、アプリケーションロジックが必要になります。
- 2つのバックエンド= 2つのクエリ言語=管理要件が異なる2つの異なるプログラム= 2つのデータベースがメモリを奪い合っています。
JSON
データ型の列に行きます。Postgresの新機能の使用を恐れないでください。Postgresチームは安定していない機能をリリースしません。そして、9.2は実際にはそれほど新しいものではありません)。さらに、9.3の新しいJSON機能を利用できるようになります。アプリケーションコード内のドキュメントを常に完全に処理している場合(SQLを使用するのではなく)、JSONを通常のtext
列に格納することもできます。