web-dev-qa-db-ja.com

MongoDBは、並べ替えのある単純なクエリで1つのインデックスのみを使用します

だから問題は、私が膨大なコレクションを持っていることであり、それらにインデックスを持つフィールドだけをフィルタリングしてソートするクエリを実行しようとしていることです。

次の2つのインデックスがあります。

db.getCollection('product').createIndex({"_type": 1, "_collectivity": 1, "own_risk": 1});
db.getCollection('product').createIndex({"price": 1});

そして、それは私が実行している単純なクエリです:

db.getCollection('product').find({
    "_type": "healthcare2",
    "_collectivity": null,
    "own_risk": 375
}).sort({price: 1}).explain()

そして、これがこのクエリのwinningPlanです:

{
  "winningPlan": {
    "stage": "FETCH",
    "filter": {
      "$and": [
        {
          "_collectivity": {
            "$eq": null
          }
        },
        {
          "_type": {
            "$eq": "healthcare2"
          }
        },
        {
          "own_risk": {
            "$eq": 375.0000000000000000
          }
        }
      ]
    },
    "inputStage": {
      "stage": "IXSCAN",
      "keyPattern": {
        "price": 1
      },
      "indexName": "price_1",
      "isMultiKey": false,
      "direction": "forward",
      "indexBounds": {
        "price": [
          "[MinKey, MaxKey]"
        ]
      }
    }
  }
}

したがって、すべてのインデックスを無視して、すべてのコレクションをスキャンします。しかし、私がヒントをしようとすると:

db.getCollection('product').find({
    "_type": "healthcare2",
    "_collectivity": null,
    "own_risk": 375
}).sort({price: 1}).hint({"_type": 1, "_collectivity": 1, "own_risk": 1})

Mongoからエラーが返されます...

error: {
    "$err" : "Executor error: Overflow sort stage buffered data usage of 33686190 bytes exceeds internal limit of 33554432 bytes",
    "code" : 17144
}

Mongoは、最初のインデックスを持つすべてのドキュメントを整理した後、priceインデックスを使用しようとしません。

だから...私の問題は何ですか?それともモンゴ? MongoDBに1つのクエリで複数のインデックスを使用させるにはどうすればよいですか?

私のMongoDBは3.0.6で、Vagrant内のUbuntuで実行されています。

4

MongoDB 2.6以降では、複数のインデックスがクエリのパフォーマンスを向上させる可能性がある場合にインデックスの交差を考慮しますが、インデックスのソートにはクエリの述語と共通のキーが必要です。シナリオでは、これは、priceがクエリに含まれていない限り、_{price:1}_のインデックスをインデックスの交差に使用できないことを意味します。

したがって、すべてのインデックスを無視して、すべてのコレクションをスキャンします。

クエリexplain()に従って実際に行われていることは、_price:1_インデックスが、インデックススキャン(IXSCAN)を介してソートされた順序で結果を返すために使用されていることです。複合インデックスでは、結果セットのメモリ内並べ替えが必要になります。これは、インデックスをヒントにして見つけた メモリ内並べ替えバッファ(32MB) のサイズよりも大きい場合があります。クエリに制限を追加して結果が32MB未満になる場合、複合インデックスは使用できる可能性がありますが、理想的ではありません。

クエリの場合、目的の並べ替え順序(および無制限の結果セット)をサポートする理想的なインデックスは、価格を含む複合インデックスです。

_db.product.createIndex({"_type": 1, "_collectivity": 1, "own_risk": 1, "price": 1});
_

詳細については、以下を参照してください。

4
Stennie

複合インデックスの最後に"price":1を追加し(他のインデックスをドロップ)、mongodは検索フェーズとソートフェーズの両方にそれを使用します。

db.getCollection('product').createIndex({
  "_type": 1,
  "_collectivity": 1,
  "own_risk": 1 ,
  "price": 1
});

オプティマイザが複合インデックスに対して{price:1}を優先する理由は、クエリが返す結果の数です。

新しいインデックスは機能しますが、結果の数がコレクションの最大サイズに近い場合、パフォーマンスの向上は期待できません。

インデックスの交差をテストすることも興味深いですが、返される結果の数が多いため、遅くなると思います。

1
Antonios