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

並べ替えは、MongoDBの`$or`および`$in`クエリでどのように機能しますか?

    注: この回答はMongoDB3.2.4に基づいています。

    explain()の使用法を発見することは価値があります MongoDBで。 explain() クエリの出力(例:db.collection.explain().find(...) )クエリで使用されているインデックスを確認し、 db.collection.explain('executionStats') また、メモリ内のSORTが原因でクエリが成功したか失敗したかが表示されます 制限。

    $ in

    $in クエリは、一連の等式クエリと考えることができます。例:{a: {$in: [1,3,5]}} {a:1}, {a:3}, {a:5}と考えることができます 。 MongoDBは$inをソートします クエリを続行する前に配列を作成し、{$in: [3,5,1]} {$in: [1,3,5]}と同じです 。

    コレクションのインデックスが

    であると仮定しましょう。
    {a:1, b:1}
    
    • aによる並べ替え

        db.coll.find({a: {$in: [1,3,5]}}).sort({a:1})
      

      MongoDBは{a:1,b:1}を使用できるようになります このクエリは{a:1}, {a:3}, {a:5}の和集合と考えることができるためインデックス。 クエリ。 {a:1}で並べ替える インデックスプレフィックスの使用を許可します 、したがって、MongoDBはメモリ内の並べ替えを実行する必要はありません。

      同じ状況がクエリにも当てはまります:

        db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({a:1})
      

      sort({a:1})以降 インデックスプレフィックス(a)も使用します この場合)、メモリ内のSORT したがって、ステージは必要ありません。

    • bによる並べ替え

      これは、aで並べ替えるよりも興味深いケースです。 。例:

        db.coll.find({a: {$in: [1,3,5]}}).sort({b:1})
      

      explain() このクエリの出力には、SORT_MERGEというステージがあります。 。 find()であることを忘れないでください クエリの一部は、{a:1}, {a:3}, {a:5}と考えることができます。 。

      クエリdb.coll.find({a:1}).sort({b:1}) メモリ内のSORTは必要ありません {a:1,b:1}の性質によるステージ インデックス:つまり、MongoDBは(ソートされた)インデックスをたどり、bでソートされたドキュメントを返すことができます。 aの等式パラメータを満たした後 。例:各a 、多くのbがあります すでにbで並べ替えられています インデックスのため。

      $inを使用する 、クエリ全体は次のように考えることができます:

      • db.coll.find({a:1}).sort({b:1})
      • db.coll.find({a:3}).sort({b:1})
      • db.coll.find({a:5}).sort({b:1})
      • 上記の個々のクエリ結果を取得し、bの値を使用してマージを実行します 。クエリはメモリ内の並べ替えステージは必要ありません 個々のクエリ結果はすでにbで並べ替えられているためです 。 MongoDBは、(既に並べ替えられた)サブクエリの結果を単一の結果にマージする必要があります。

      同様に、クエリ

        db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({b:1})
      

      SORT_MERGEも使用します ステージであり、上記のクエリと非常によく似ています。違いは、個々のクエリが範囲に基づいてドキュメントを出力することです。 bすべての代わりに b )各abで並べ替えられます インデックス{a:1,b:1}による )。したがって、クエリにはメモリ内の並べ替えステージは必要ありません。

    $または

    $orの場合 インデックスを使用するためのクエリ、すべての句$orで 式にはインデックスが関連付けられている必要があります 。この要件が満たされている場合、クエリでSORT_MERGEを使用することができます。 $inのようなステージ クエリ。例:

    db.coll.explain().find({$or:[{a:1},{a:3},{a:5}]}).sort({b:1})
    

    ほぼ同じクエリプラン、インデックスの使用、およびSORT_MERGE $inのようにステージングする 上記の例。基本的に、クエリは次のように考えることができます:

    • db.coll.find({a:1}).sort({b:1})
    • db.coll.find({a:3}).sort({b:1})
    • db.coll.find({a:5}).sort({b:1})
    • 上記の個々のクエリ結果を取得し、bの値を使用してマージを実行します 。

    $inと同じように 前の例。

    ただし、このクエリ:

    db.coll.explain().find({$or:[{a:1},{b:1}]}).sort({b:1})
    

    インデックスを使用できません{b:1}がないため 索引)。このクエリによりコレクションスキャンが実行されるため、メモリ内の並べ替えステージがあります インデックスが使用されていないため。

    ただし、インデックスを作成する場合{b:1} 、クエリは次のように進行します:

    • db.coll.find({a:1}).sort({b:1})
    • db.coll.find({b:1}).sort({b:1})
    • 上記の個々のクエリ結果を取得し、bの値を使用してマージを実行します (インデックス{a:1,b:1}のため、両方のサブクエリですでに並べ替えられています および{b:1}

    MongoDBは、{a:1}の結果を結合します および{b:1} クエリを実行し、結果に対してマージを実行します。マージプロセスは線形時間です。 O(n)

    結論として、$or クエリでは、すべての用語にsort()を含むインデックスが必要です。 ステージ。そうしないと、MongoDBはメモリ内の並べ替えを実行する必要があります。




    1. SQLを使用したMongoDB結合のリンクと作成:パート3

    2. MongoDBの再帰ドキュメントの構造とクエリ構文?

    3. マングースでpromiseを使用する際の問題

    4. $nearを使用してドキュメントに保存されている距離でドキュメントをフィルタリングする