5

私は、各ユーザーが独自のjson/documentデータベースを持っている必要があるサービスを実装しています。ユーザーがjsonドキュメントをクエリできるようにするだけでなく、データベースは複数のドキュメントを含むACIDトランザクションもサポートする必要があるため、Couch / Mongoまたはその他のNoSQLデータベースを使用して破棄しました(RavenDBはUnixシステムで実行する必要があるため使用できません)。

それを念頭に置いて、SQLデータベースの上にそれを実装する方法を考えようとしてきました。これが私がこれまでに思いついたものです:

CREATE TABLE documents (
  id INTEGER PRIMARY KEY,
  doc TEXT
);

CREATE TABLE indexes (
  id INTEGER PRIMARY KEY,
  property TEXT,
  value TEXT,
  document_id INTEGER
)

各ユーザーは、これら2つのテーブルを含むデータベースを持っており、システムが「インデックス」テーブルに適切にデータを入力できるように、ユーザーはクエリを実行する必要のあるフィールドを宣言する必要があります。したがって、ユーザー「A」が「名前」と「年齢」によるクエリを有効にするようにアカウントを構成すると、そのユーザーが「名前」または「年齢」プロパティを持つドキュメントを挿入するたびに、システムは「インデックス」にもレコードを挿入します。テーブル。「property」列には名前/年齢が含まれ、「value」にはプロパティ値が含まれ、「document_id」は対応するドキュメントを指します。

たとえば、ユーザーが次のドキュメントを挿入するとします。

'{"name" : "Foo", "age" 43}'

これにより、「documents」テーブルに挿入され、「indexes」テーブルにさらに2つの挿入が行われます。

INSERT INTO documents (id,doc) VALUES (1, '{"name" : "Foo", "age" 43}');
INSERT INTO indexes (property, value, document_id) VALUES ('name', 'foo', 1);
INSERT INTO indexes (property, value, document_id) VALUES ('age', '43', 1);

次に、ユーザー「A」がサービスに次のクエリを送信したとします。

'{"name": "Foo", "age": 43}' //(the queries are also json documents).

このクエリは、次のSQLに変換されます。

SELECT doc FROM documents
WHERE id IN (SELECT document_id FROM indexes
             WHERE document_id IN (SELECT document_id FROM indexes
                                   WHERE property = 'name' AND value = 'Foo')
             AND property = 'age' AND value = '43') 

私の質問:

  • ユーザーがクエリで多数の条件(たとえば20〜30のAND条件)を使用できる可能性があることを知っていると、サブクエリのネストが非常に高くなり、上記のSELECTクエリはほとんどのデータベースシステムでどれほど効率的ですか( postgres、mysql ...)?
  • 上記のソリューションは、最終的に数百万/数十億のjsonドキュメントを含むデータベースで実行可能ですか?
  • 私の要件を満たすためのより良い方法はありますか?
  • 複数のドキュメントを含むACIDトランザクションを実行でき、Unixシステムで実行できるスケーラブルなドキュメントデータベースはありますか?
4

1 に答える 1

5

あなたのindexesテーブルはとして知られているものですEntity-Attribute-Value

EAVテーブルは、情報を保存し、エンティティを知っているときにそれを呼び出すのに適しています。 (あなたの場合、あなたが知っているときにすべてのindexes行を見つけますdocument_id。)

しかし、逆の場合はひどいです。エンティティを検索するための属性と値の組み合わせを提供します。これは、最終的なクエリに含まれているものとまったく同じです。同じ属性と値の組み合わせ(などname=fooを共有するエンティティが増えると、クエリのパフォーマンスが低下します。

したがって、最初の2つの質問に答えるには、次のようにします
。1.記述されているクエリでは、プロパティnを検索するときにサブクエリが必要です。nこれは、成長するにつれて非常に不十分にスケーリングしnます。
2.レコードの数が増えると、特に数百万/数十億のレコードで劣化します。

一般的に、について読んだ場合EAV、人々はそれを避けることを強くお勧めします。


さらに悪いことに、SQLには実際には良い代替手段がありません。検索を最適化する標準的な方法は、並べ替えられたデータセットとして簡単にモデル化できるインデックスを使用することです。ただし、その場合は多くのインデックスが必要になります。
- 3つの列すべてを検索する場合、のインデックス(fieldX, fieldY, fieldZ)優れています。
-しかし、あなたがただで検索しなければならないなら、それはひどいです。 fieldZ


これを、固定数の列を持つ従来のテーブルで再モデル化し、必要になるすべてのインデックスの組み合わせを適用するスペースがある場合、それが最もパフォーマンスの高いモデルになります。

列の数を修正できない場合(常に新しいものがありますproperties、および/またはインデックスのさまざまな組み合わせすべてのためのスペースがない場合は、EAVで立ち往生しているようです。これは機能しますが、「瞬時の」結果に関してはあまり拡張性がありません。

注: EAVを使用する場合は、このクエリ構造をテストしましたか?

  SELECT
    document_id
  FROM
    indexes
  WHERE
       (property = 'name' AND value = 'Foo')
    OR (property = 'age'  AND value = '43' )
  GROUP BY
    document_id
  HAVING
    COUNT(*) = 2

これは、が一意であることを前提としてい(document_id, property, value)ます。そうしないと、1つのドキュメントに2回含まれる可能性があるため、句('name', 'foo')を渡します。COUNT(*)

于 2012-06-25T16:00:39.117 に答える