View a markdown version of this page

インデックスのみのスキャン (対象クエリ) - Amazon DocumentDB

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

インデックスのみのスキャン (対象クエリ)

インデックスのみのスキャン (対象クエリとも呼ばれます) は、Amazon DocumentDB が基になるドキュメントを読み取らずに、インデックスに保存されているフィールドからクエリに完全に応答する最適化です。クエリに必要な値はインデックスに既に存在するため、Amazon DocumentDB は一致する各ドキュメントの取得をスキップできるため、ランダム I/O を回避し、ドキュメント全体を読み取るためのデコードコストを回避できます。クエリプランでは、インデックスのみのスキャンは、 IXSCAN (インデックススキャン) または COLLSCAN (コレクションスキャン) の代わりにIXONLYSCANステージとして表示されます。これにより、I/O が削減され、サポートされているクエリのクエリレイテンシーが大幅に短縮されます。

クエリは、1 つのインデックスに存在する少数のフィールドのみ、特にドキュメント自体が大きい場合、インデックスのみのスキャンに適しています。一般的な例は、より広範な複合インデックスからいくつかのフィールドを読み取るダッシュボード、分析ロールアップ、ルックアップです。

クエリの結果は、インデックスのみのスキャンを使用するかどうかにかかわらず同じです。クエリプランと実行される I/O の量のみが変わります。

注記

インデックスのみのスキャンのサポートは、Amazon DocumentDB エンジンのバージョンによって異なります。

  • 複数の非_idフィールドを含む対象find射影には、エンジンバージョン 8.0.2 以降が必要です。以前のバージョンでは、対象find射影には最大 1 つの非 _idフィールドを含めることができます。2 つ以上のフィールドを持つ射影は、通常のインデックススキャンまたはコレクションスキャンにフォールバックします。

  • 対象となる などの集約パイプラインのインデックスのみのスキャンには$group、エンジンバージョン 8.0.2 以降が必要です。

Amazon DocumentDB がインデックスのみのスキャンを使用する場合

Amazon DocumentDB は、1 つのインデックスにオペレーションが読み取るすべてのフィールドが含まれている場合、次のオペレーションのインデックスのみのスキャンを考慮します。

対象find射影

find クエリは、その射影が 1 つ以上の最上位フィールドの単純な包含であり、すべての射影フィールドが 1 つのインデックスに存在する場合に認定されます。たとえば、 で複合インデックスがあるとすると{ customerId: 1, status: 1, total: 1 }、次のクエリがカバーされます。射影された 3 つのフィールドはすべてインデックスに存在し、明示的に除外_idされます。(複数のフィールド_id以外の射影をカバーするには、エンジンバージョン 8.0.2 以降が必要です)。

db.orders.createIndex({ customerId: 1, status: 1, total: 1 }) db.orders.find( { customerId: 42 }, { _id: 0, customerId: 1, status: 1, total: 1 } )

落札者はステージを使用しIXONLYSCAN、一致するドキュメントをストレージから取得しません。

{ "stage": "IXONLYSCAN", "indexName": "customerId_1_status_1_total_1", "direction": "forward", "indexCond": { "$and": [ { "customerId": { "$eq": 42 } } ] } }
注記

対象findクエリでは、結果のフィールドは、射影にリストされた順序やドキュメントに保存された順序ではなく、インデックスの順序 (フィールドがインデックス定義に表示される順序) で返されます。これは、対象クエリの MongoDB の動作と一致します。コレクションスキャンによって応答されたクエリは、代わりにストアドドキュメントの順序でフィールドを返します。

対象$group集計

$group ステージは通常、少数のフィールド (グループキーとそのアキュムレータへの入力) のみを読み取りますが、多くの場合、先頭の なしで実行されます$match。カバーインデックスがない場合、Amazon DocumentDB はコレクション内のすべてのドキュメントを読み取り、デコードして、これらの少数のフィールドをグループ化にフィードします。

対象$groupステージを含む集約パイプラインのインデックスのみのスキャンは、エンジンバージョン 8.0.2 以降で使用できます。

単一のインデックスにパイプラインプレフィックスが読み取るすべてのフィールドが含まれている場合、Amazon DocumentDB はグループの下にインデックスのみのスキャンを配置し、インデックスから直接それらのフィールドを読み取ることができます。ステータス別に注文をグループ化し、合計を合計し、 に複合インデックスを持つパイプラインを考えてみましょう{ status: 1, total: 1 }。

db.orders.createIndex({ status: 1, total: 1 }) db.orders.aggregate([ { $group: { _id: "$status", revenue: { $sum: "$total" } } } ])

パイプラインは statusと のみを読み取りtotal、どちらもインデックスにあるため、グループはコレクションスキャンIXONLYSCANの代わりに からフィードされます。

// Without a covering index $group <- COLLSCAN (reads and decodes every full document) // With a covering index on { status, total } $group <- IXONLYSCAN over { status, total } (reads only the referenced fields)

$group がサポートされている$limit前の先頭$matchの $sort、、$skip、または 。ただし、パイプラインをカバーするには、これらのステージが参照するすべてのフィールド ($matchフィルターフィールドや$sortキーなど) も同じインデックスに存在する必要があります。インデックスに参照フィールドがない場合、Amazon DocumentDB はコレクションまたはインデックススキャンにフォールバックします。

注記

find 射影とは異なり、 $groupには暗黙的にドキュメント は含まれません_id。_id の $groupはドキュメント識別子ではなくグループキーであるため、パイプラインをカバーする_idためにインデックスにドキュメントを含める必要はありません。

対象クエリの要件

Amazon DocumentDB がインデックスのみのスキャンを使用するには、次のすべてを保持する必要があります。

  • 単一のインデックスには、クエリが読み取るすべてのフィールドが含まれます。これにはfind、 の射影フィールド、グループキー、アキュムレータ入力、および対象$groupパイプラインのフィルターまたはソートフィールドが含まれます。インデックスに 1 つのフィールドがない場合、クエリをカバーできません。

  • 射影には、最上位フィールド ( の場合) が含まれます。 find除外射影、計算フィールド、 や などの射影演算子$slice$elemMatchは対象外です。

  • _id フィールドは ( の場合) が考慮されます。 find_id はデフォルトで含まれるため、 などの一般的な複合インデックス{ a: 1, b: 1 }は をカバーしませんfind({}, { a: 1, b: 1 })。暗黙的な _idはインデックスに含まれません。プロジェクション ({ _id: 0, a: 1, b: 1 }) _id から除外するか、インデックス_idに追加します。

  • フィルターはインデックスによって完全に満たされます。Amazon DocumentDB がクエリ述語の一部をインデックスバインドに変換できない場合、その部分は残差フィルターとして保持され、ドキュメントを読み取りて評価し、スキャンをインデックスのみのスキャンに変換しません。$mod、$ne、、 などの演算子は$nin、残余フィルターを$exists残します。

  • 射影フィールドはマルチキー (配列) 列ではありません。「制限事項」を参照してください。

制限事項

次のケースでは、インデックスのみのスキャンを使用できず、通常のインデックススキャンまたはコレクションスキャンにフォールバックすることはできません。これは予想される動作であり、結果の正確性には影響しません。

  • マルチキー (配列) フィールド。フィールドが任意のドキュメントで配列値を保持したことがある場合、そのインデックス列はマルチキーです。マルチキーインデックスは配列要素ごとに 1 つのエントリを保存するため、元の配列をインデックスから再構築することはできません。このようなフィールドを読み取るクエリは対象になりません。

  • ドットまたはネストされたパス。インデックスにそのパスが含まれている場合でも、 などのネストされたパスの射影またはフィールド参照"address.city"は対象外です。

  • 除外、計算、または演算子の射影。{ b: 0 }、、 などの射影には完全なドキュメント{ a: { $slice: 5 } }が必要であり{ total: { $add: ["$price", "$tax"] } }、対象にはなりません。

  • 集計でのドキュメント全体の参照。ドキュメント全体を参照$groupする ( など{ $push: "$$ROOT" }) は、インデックスがドキュメント全体を再構築できないため、カバーできません。

  • より前のステージの再形成$group。がパイプラインの対象$groupから除外する前に表示されるドキュメント ($project、$unwind、、 など$lookup) $addFieldsを再構成するステージ。

  • 文字列述語の照合不一致。クエリの照合順序がインデックスの照合順序と異なる場合、文字列述語をインデックスで処理して残余フィルターを残すことはできません。これにより、ドキュメントが強制的に取得されます。数値および型ベースの述語は影響を受けません。

インデックスのみのスキャンの確認

explain("executionStats") 出力を使用して、クエリがインデックスのみのスキャンによって処理され、ドキュメントに影響を与えていないことを確認します。次の 2 つのものを探します。

  • 獲得プランは IXONLYSCANステージを使用します。

  • そのステージのdocsExamined値は です 0 ( は totalDocsExaminedです0)。つまり、クエリはドキュメントを読み取らずにインデックスから完全に回答されました。

db.orders.find( { customerId: 42 }, { _id: 0, customerId: 1, status: 1, total: 1 } ).explain("executionStats").executionStats
{ "executionSuccess": true, "nReturned": "2", "executionTimeMillis": "0.714", "totalDocsExamined": "0", "executionStages": { "stage": "IXONLYSCAN", "nReturned": "2", "indexName": "customerId_1_status_1_total_1", "direction": "forward", "docsExamined": "0" } }
注記

IXONLYSCAN ステージのゼロ以外のdocsExamined値は、インデックスにデータが含まれていることを意味しますが、Amazon DocumentDB は引き続きストレージをチェックして、各ドキュメントバージョンが表示されていることを確認します。これは、コレクションに古いドキュメントバージョンのガベージコレクションがまだ再利用されていない最近の書き込みがある場合に発生する可能性があります。ガベージコレクションがこれらのドキュメントを処理すると、 は にdocsExaminedドロップします0。その時点で、クエリは対象スキャンを最大限に活用します。ガベージコレクションの詳細については、「」を参照してくださいAmazon DocumentDB のガベージコレクション。docsExamined メトリクスの詳細については、「クエリプラン分析」を参照してください。

ベストプラクティス

  • 最も頻度の高いクエリプロジェクトまたはグループを含む複合インデックスを設計して、それらのクエリをカバーできるようにします。

  • _id がカバーインデックスの一部でない限り、find射影 ({ _id: 0, ... }) _idから除外します。

  • マルチキー列はインデックスのみのパスを失格にするので、クエリをカバーしようとするときは、配列 (マルチキー) フィールドのインデックス作成は避けてください。

  • ガベージコレクションが書き込みワークロードに対応できるようにして、対象スキャンがドキュメントへのアクセスをスキップし、 にdocsExaminedとどまるようにします0。詳細については、「Amazon DocumentDB のガベージコレクション」を参照してください。