sql >> データベース >  >> NoSQL >> MongoDB

MongoDb:多くの検索可能なフィールドを持つデータに適切な(複合)インデックスを作成する方法

    これが何を意味するのかを例で説明しようと思います。 Bツリーに基づくインデックスは、mongodb固有のものではありません。対照的に、それはかなり一般的な概念です。

    したがって、インデックスを作成すると、データベースに何かを見つけるためのより簡単な方法が表示されます。ただし、このインデックスは、元のドキュメントの場所を指すポインタとともにどこかに保存されます。この情報は順序付けられており、非常に優れたプロパティを持つバイナリツリーと見なすことができます。検索はO(n)から削減されます。 (線形スキャン)からO(log(n)) 。スペースを半分にトリミングするたびに、これははるかに高速です(10 ^ 6から20ルックアップに時間を短縮できる可能性があります)。たとえば、フィールド{a : some int, b: 'some other things'}を持つ大きなコレクションがあります。 そして、それをaでインデックス付けすると、aでソートされた別のデータ構造になります。 。このように見えます(これは、別のコレクションであるという意味ではありません。これはデモンストレーション用です):

    {a : 1, pointer: to the field with a = 1}, // if a is the smallest number in the starting collection
    ...
    {a : 999, pointer: to the field with a = 990} // assuming that 999 is the biggest field
    

    したがって、現在、フィールドa =18を検索しています。すべての要素を1つずつ調べる代わりに、真ん中に何かを取り、18より大きい場合は、下部を半分に分割して、そこで要素をチェックします。 。 a =18が見つかるまで続行します。次に、ポインターを調べて、元のフィールドを抽出することを確認します。

    複合インデックスの状況も同様です(1つの要素で並べ替える代わりに、多くの要素で並べ替えます)。たとえば、コレクションがあります:

    { "item": 5, "location": 1, "stock": 3, 'a lot of other fields' }  // was stored at position 5 on the disk
    { "item": 1, "location": 3, "stock": 1, 'a lot of other fields' }  // position 1 on the disk
    { "item": 2, "location": 5, "stock": 7, 'a lot of other fields' }  // position 3 on the disk
    ... huge amount of other data
    { "item": 1, "location": 1, "stock": 1, 'a lot of other fields' }  // position 9 on the disk
    { "item": 1, "location": 1, "stock": 2, 'a lot of other fields' }  // position 7 on the disk
    

    インデックスが必要です{"item":1、 "location":1、 "stock":1}。ルックアップテーブルは次のようになります(もう一度-これは別のコレクションではなく、デモンストレーション用です):

    { "item": 1, "location": 1, "stock": 1, pointer = 9 }
    { "item": 1, "location": 1, "stock": 2, pointer = 7 }
    { "item": 1, "location": 3, "stock": 1, pointer = 1 }
    { "item": 2, "location": 5, "stock": 7, pointer = 3 }
    .. huge amount of other data (but not necessarily here. If item would be one it would be somewhere next to items 1)
    { "item": 5, "location": 1, "stock": 3, pointer = 5 }
    

    ここでは、すべてが基本的にアイテム、場所、ポインタの順に並べ替えられていることを確認してください。単一のインデックスの場合と同じように、すべてをスキャンする必要はありません。 item = 2, location = 5 and stock = 7を検索するクエリがある場合 item = 2のドキュメントがどこにあるかをすばやく特定できます 次に、同じ方法で、location 5を使用してこれらのアイテムのどこにアイテムがあるかをすばやく特定します。 など。

    そして今、興味深い部分 。また、インデックスを1つだけ作成しました(これは複合インデックスですが、それでも1つのインデックスです)。これを使用して、要素をすばやく見つけることができます

    • itemのみ 。本当に私たちがする必要があるのは最初のステップだけです。したがって、別のインデックス{location:1}はすでに複合インデックスでカバーされているため、作成する意味はありません。
    • また、item and by locationでのみすばやく見つけることができます (2つのステップだけが必要です)。

    クールな1つのインデックスですが、3つの異なる方法で役立ちます。ただし、ちょっと待ってください。item and stockで検索したい場合はどうでしょうか。 。ああ、このクエリも高速化できるようです。 log(n)で特定のアイテムを持つすべての要素を見つけることができ、...ここで停止する必要があります-魔法は終了しました。それらすべてを繰り返す必要があります。しかし、それでもかなり良いです。

    しかし、それが他の質問に役立つかもしれません。 locationでクエリを見てみましょう すでに注文されたようです。しかし、それを見ると、これは混乱していることがわかります。最初に1つ、最後に1つ。それはあなたをまったく助けることができません。

    これでいくつかのことが明らかになることを願っています:

    • インデックスが優れている理由(O(n)から潜在的にO(log(n))に時間を短縮する
    • 複合インデックスが一部のクエリに役立つのに、その特定のフィールドにインデックスを作成しておらず、他のクエリに役立つのはなぜですか。
    • 複合インデックスの対象となるインデックス
    • インデックスが害を及ぼす可能性がある理由(維持する必要のある追加のデータ構造を作成する)

    そして、これは別の有効なことを伝えるはずです:インデックスは銀の弾丸ではありません 。すべてのクエリを高速化することはできないため、すべてのフィールドにインデックスを作成することですべてが超高速になると考えるのはばかげているように思えます。



    1. MongoDBの配列から0の後に>=1が続く場合は、0の値を削除します

    2. pymongo:MongoClientまたはConnection

    3. MongoDB Atlasの概要:パート1

    4. Mongodbはエラーメッセージを取得しますMongoError:アクティビティでのパスの衝突