View a markdown version of this page

キャッシュフィルターの計画 - Amazon DocumentDB

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

キャッシュフィルターの計画

インデックスフィルターとも呼ばれるプランキャッシュフィルターは、クエリプランナーが特定のクエリシェイプについて考慮できるインデックスのセットを制限します。クエリがフィルターを持つシェイプと一致する場合、プランナーはコレクション上のすべてのインデックスを評価するのではなく、そのフィルター内の という名前のインデックスからのみプランを選択します。

クエリシェイプは、クエリ述語、ソート仕様、コレクション名前空間の組み合わせで、述語値が正規化されます。値のみが異なる 2 つのクエリはシェイプを共有するため、1 つのフィルターですべてのクエリをカバーします。の出力ではplanCacheListFilters、正規化された値は として表示されます"@"。

プランキャッシュフィルターを使用すると、プランを固定できるため、データ分散やインデックスの変更によるインデックスの選択が遅くなるのを回避できます。フィルターには次のプロパティがあります。

  • アプリケーションの変更は必要ありません。フィルタはデータベースコマンドで設定され、サーバーに適用されるため、コードのデプロイなしでリグレッションを軽減できます。これは、すべての通話サイトに追加hintする必要がある との主な違いです。

  • スコープは 1 つのクエリシェイプです。シェイプは、完全なクエリではなく、コレクション、述語、ソートによって定義されるため、フィルターはそのシェイプに一致するクエリのみを制限します。同じコレクションに対する他のクエリは、引き続き通常どおり計画されます。

  • 変更は耐久性があります。フィルターは、インスタンスの再起動とエンジンのパッチ適用全体で保持されます。コレクションを削除すると、そのフィルターが削除されます。

  • 変更は元に戻されます。フィルターをクリアするとシェイプが通常のコストベースの計画に戻るため、フィルターは根本的な原因を調査しながらワークロードを安定させる低リスクの方法です。

サポートされているコマンド

プランキャッシュフィルターには、プランナーバージョン 2.0 以降が必要です。フィルターを適用できるコマンドは、次の表に示すように、プランナーバージョンと Amazon DocumentDB マイナーバージョンによって異なります。

プランキャッシュフィルターのコマンドサポート
コマンド プランナーの最小バージョン 最小マイナーバージョン

find

2.0

5.0.0、8.0.0

count

2.0

5.0.0、8.0.0

update

2.0

5.0.2、8.0.2

delete

2.0

5.0.2、8.0.2

findAndModify

2.0

5.0.2、8.0.2

distinct

3.0

8.0.0

aggregate

3.0

8.0.2

注記

プランナーバージョン 3.0 は Amazon DocumentDB 8.0 でのみ使用できます。コマンドdistinctと aggregate コマンドにはプランナーバージョン 3.0 が必要なため、これら 2 つのコマンドの計画キャッシュフィルターは Amazon DocumentDB 8.0 でのみ使用できます。プランナーバージョン 2.0 をサポートする Amazon DocumentDB 5.0 では、フィルターは find、、count、delete、updateおよび findAndModify コマンドに適用されます。

aggregate コマンドの場合、シェイプはパイプラインの前面から取得されます。先頭はフィルター$matchを提供し、先頭はソートを提供する$sort直後に を提供します。 $skip と はシェイプに影響を与え$limitず、それ以降のステージも影響を受けません。

Amazon DocumentDB は、パイプラインを計画する前に最適化し、計画キャッシュフィルターは最適化されたパイプラインと照合されます。したがって、プランナーに表示されるフィルターとソートは、作成したステージとは異なる可能性があります。たとえば、パイプラインの前面にある 2 つの隣接する$matchステージが 1 つの$and述語に結合されます。

db.orders.aggregate([ { $match: { status: "SHIPPED" } }, { $match: { region: "us-east-1" } }, { $group: { _id: "$customerId", total: { $sum: "$amount" } } } ])

プランナーは $matchに 1 つ表示されるため{$and: [{status: ...}, {region: ...}]}、フィルターはその結合述語に設定する必要があります。

db.runCommand({planCacheSetFilter: "orders", query: { $and: [ { status: "SHIPPED" }, { region: "us-east-1" } ] }, indexes: [ "status_1_region_1" ]})

$lookup ステージまたは $graphLookupステージの外部コレクションに設定されたフィルターは、その外部コレクションのスキャンに使用されるインデックスを駆動します。

サポートされているクエリシェイプ

Amazon DocumentDB 5.0.2 および 8.0.2 以降では、プランキャッシュフィルターを持つクエリシェイプに次の演算子を表示できます。

  • $text。 検索文字列は正規化されるため、検索する用語だけが異なるクエリは 1 つのシェイプを共有します。

  • 「$near」および「$nearSphere」。どちらの演算子も同じ形状に正規化されます。座標、$minDistance、 $maxDistanceはシェイプの一部ではありません。

  • 「$geoWithin」および「$geoIntersects」。GeoJSON ジオメトリタイプはシェイプの一部であるため、PolygonクエリとMultiPolygonクエリは異なるシェイプです。座標はシェイプの一部ではありません。

  • $regex、 フィールドで直接使用する場合。パターンとオプションは正規化されるため、同じフィールドのすべての正規表現は 1 つのシェイプを共有します。

$jsonSchema、、$exprまたは を使用するクエリシェイプのフィルターの設定はエラーコード 303 で失敗します$sampleRate。また、次のシェイプでも失敗します。これらのいずれかを使用するクエリは、フィルターなしで計画されます。

  • 、$in、$ninまたは 内に$regexネストされた $all。正規表現とリテラル値を混在させる配列はインデックスに対して評価できないため、そのシェイプのフィルターを適用することはできません。

  • のソート仕様{$natural: 1}。$natural ソートはコレクションスキャンをリクエストしますが、プランナーをインデックスに制限することはできません。

フィルターの設定、一覧表示、クリア

計画キャッシュフィルターを設定するには、 planCacheSetFilter コマンドを使用します。query フィールドと sortフィールドは一緒にクエリシェイプを指定し、プランナーがそのシェイプについて考慮できるインデックス名をindexes一覧表示します。

db.runCommand({ planCacheSetFilter: <collection>, query: <query>, sort: <sort>, // optional indexes: [ <index1>, <index2>, ...], comment: <any> // optional })

たとえば、次のコマンドは、プランナーをソート{a: {$eq: "@"}, b: {$eq: "@"}}なしでシェイプのa_1インデックスに制限します。

db.runCommand({planCacheSetFilter: "foo", query: { a: 1, b: 1 }, sort: {}, indexes: [ "a_1" ]})

既にあるシェイプのフィルターを設定すると、既存のフィルターが置き換えられます。次の 2 つのコマンドを実行した後、シェイプのフィルター{a: {$eq: "@"}, b: {$eq: "@"}}は になります["b_1"]。

db.runCommand({planCacheSetFilter: "foo", query: { a: 1, b: 1 }, sort: {}, indexes: [ "a_1" ]}) db.runCommand({planCacheSetFilter: "foo", query: { a: 6, b: 10 }, sort: {}, indexes: [ "b_1" ]})

コレクション上のすべてのフィルターを一覧表示するには、 planCacheListFilters コマンドを使用します。

db.runCommand({planCacheListFilters: <collection>})

出力には、保存された各シェイプとその正規化された値と許可されたインデックスリストが表示されます。

{ "filters" : [ { "query" : { "a" : { "$eq" : "@" } }, "sort" : { }, "indexes" : [ "a_1" ] }, { "query" : { "a" : { "$gt" : "@" } }, "sort" : { "a" : 1 }, "indexes" : [ "a_1_b_1" ] } ], "ok" : 1 }

演算子は保持され、値のみが に置き換えられます"@"。などの暗黙的な等価性{a: 1}は、明示的な形式でリストされ{"a": {"$eq": "@"}}、$in配列の要素は全体として として置き換えられます{"a": {"$in": "@"}}。ソートのないフィルターセットは、空のsortドキュメントとともに一覧表示されます。

フィルターを削除するには、 planCacheClearFilters コマンドを使用します。

db.runCommand({ planCacheClearFilters: <collection>, query: <query pattern>, // optional sort: <sort specification>, // optional comment: <any> // optional })

コレクション上のすべてのフィルターをクリアするには、 queryと の両方を省略しますsort。

db.runCommand({planCacheClearFilters: "foo"})

query と の両方を指定すると、その正確なソートを持つフィルターのみがsortクリアされます。の値はquery正規化されないため、代表的な値はすべて機能します。ソートなしで設定されたフィルターのみをクリアするには、空のsortドキュメントを渡します。

db.runCommand({planCacheClearFilters: "foo", query: {a: 1}, sort: {a: 1}}) db.runCommand({planCacheClearFilters: "foo", query: {a: 1}, sort: {}})

フィルターが適用されていることを確認する

explain 出力には、プランキャッシュフィルターのステータスを報告する 2 つのフィールドが含まれます。

  • indexFilterSet は、クエリの形状のコレクションにフィルターが存在するtrue場合です。

  • indexFilterApplied は、そのフィルターのリストからインデックスを使用してクエリが計画されたtrue場合にのみ発生します。

Amazon DocumentDB 5.0.2 および 8.0.2 以降、これらのフィールドは、プランキャッシュフィルターをサポートするすべてのコマンドと、それらのコマンドのプロファイラー出力でレポートされます。以前のマイナーバージョンでは、これらは find コマンドに対してのみ報告されました。explain 出力の読み取りの詳細については、「」を参照してくださいクエリプラン分析。

フィルターは、適用せずにクエリシェイプを一致させることができます。フィルターのリスト内のインデックスのいずれもクエリを処理できない場合、プランナーはフィルターなしで再計画し、コストに関するインデックスを選択します。この場合、 indexFilterSetは trueで、 indexFilterAppliedは ですfalse。これは、名前付きインデックスがクエリのフィールドをカバーしない場合、名前付きインデックスが存在しない場合、または$regexシェイプがアンカーされていないパターンや大文字と小文字を区別しないパターンなどのインデックス境界を生成できない場合に発生します。

例

次の例では、 ordersコレクションと、これらのインデックスを持つ $lookup customersコレクションを使用しています。

db.orders.createIndex({ status: 1 }) // status_1 db.orders.createIndex({ status: 1, orderDate: 1 }) // status_1_orderDate_1 db.orders.createIndex({ customerId: 1 }) // customerId_1 db.customers.createIndex({ customerId: 1 }) // customerId_1

例: findクエリを複合インデックスに固定する

でフィルタリングstatusし、 でソートするクエリを考えてみましょうorderDate。

db.orders.find({ status: "SHIPPED" }).sort({ orderDate: 1 })

複合インデックスは述語とソートの両方status_1_orderDate_1を満たすため、個別のソートは必要ありません。プランナーが代わりに を選択した場合status_1、クエリは結果をソートする必要があります。これによりステージが追加され、一致する注文の数が増えるSORTにつれてコストが高くなります。プランナーをこのシェイプの複合インデックスに制限するには:

db.runCommand({planCacheSetFilter: "orders", query: { status: "SHIPPED" }, sort: { orderDate: 1 }, indexes: [ "status_1_orderDate_1" ]})

値はシェイプから正規化されるため、この 1 つのフィルターは { status: "PENDING" }、{ status: "CANCELLED" }、および同じソートstatusで の他のすべての値もカバーします。同じ述語を別のソートでカバーしたり、別のシェイプであるソートなしでカバーしたりすることはありません。でフィルターが有効になったことを確認しますexplain。

db.orders.find({ status: "SHIPPED" }).sort({ orderDate: 1 }).explain()

出力は indexFilterSet: trueと を報告しindexFilterApplied: true、IXSCANステージ名は ですstatus_1_orderDate_1。

例: を選択的インデックスupdateに固定する

更新は、書き込む前に変更するドキュメントを見つける必要があり、そのルックアップは読み取りと同じ方法でインデックスを使用します。述語を複数のインデックスで提供できる場合、プランナーが選択するインデックスによって、更新が検査するドキュメントの数が決まります。

db.orders.updateMany( { customerId: 4815, status: "PENDING" }, { $set: { status: "CANCELLED" } } )

customerId_1 と の両方がこの述語を提供status_1できます。更新を に固定するにはcustomerId_1:

db.runCommand({planCacheSetFilter: "orders", query: { customerId: 4815, status: "PENDING" }, indexes: [ "customerId_1" ]})

書き込みコマンドのフィルタには、Amazon DocumentDB 5.0.2 または 8.0.2 とプランナーバージョン 2.0 以降が必要です。更新explainの を使用して検証します。

db.runCommand({explain: {update: "orders", updates: [{ q: { customerId: 4815, status: "PENDING" }, u: { $set: { status: "CANCELLED" } }, multi: true }]}})

成功プランは、 IXSCAN上の よりも UPDATE ステージですcustomerId_1。シェイプには書き込みのタイプが含まれていないため、このクエリシェイプを使用する deleteおよび findAndModify コマンドにも同じフィルターが適用されます。

例: aggregateパイプラインと$lookup外部コレクションを固定する

集計の場合、シェイプは先頭ステージと$sort直後の$matchステージから取得されます。$group や など、それを超えるステージ$projectはシェイプの一部ではありません。

db.orders.aggregate([ { $match: { status: "SHIPPED" } }, { $group: { _id: "$customerId", total: { $sum: "$amount" } } } ])

$match 述語に設定されたフィルターは、 の読み取りに使用されるインデックスを駆動しますorders。

db.runCommand({planCacheSetFilter: "orders", query: { status: "SHIPPED" }, indexes: [ "status_1" ]})

フィルターは、 $lookupまたは $graphLookupステージが結合するコレクションにも適用されます。フィルターは、パイプラインが実行されるコレクションではなく、外部コレクションに設定されます。次のパイプラインでは、 ordersは外部コレクションで、 は外部コレクションcustomersです。

db.orders.aggregate([ { $lookup: { from: "customers", localField: "customerId", foreignField: "customerId", as: "customer" } } ])

結合は外部ドキュメントごとに 1 customers回プローブされるため、そこで選択されたインデックスは繰り返し適用され、コストはパイプライン全体に乗算されます。そのスキャンを特定のインデックスに固定するには、結合キーの等価シェイプcustomersのフィルターを に設定します。

db.runCommand({planCacheSetFilter: "customers", query: { customerId: 1 }, indexes: [ "customerId_1" ]})

値はシェイプから正規化されるため、1上記の値はプレースホルダーであり、どの値でも同じフィルターが生成されます。外部コレクションフィルターが適用されると、最上位の indexFilterSetフィールドと indexFilterAppliedフィールドは を報告しtrue、選択したフィルターのインデックスは、獲得プランの外部側に表示されます。のフィルターには、Amazon DocumentDB 8.0.2 とプランナーバージョン 3.0 aggregateが必要です。

ヒントとインデックスの変更を含む動作

  • プランキャッシュフィルターは、 よりも優先されますhint。Amazon DocumentDB は最初にフィルターを適用し、次にフィルターの許可されたインデックスリスト内にヒントを適用します。ヒントがフィルターが許可するインデックスに名前を付ける場合、そのインデックスが使用されます。ヒントがフィルターで許可されていないインデックスに名前を付けると、ヒントは無視され、プランナーは許可されたインデックスの中からコストに基づいて選択します。どちらのヒントフォームも、インデックスに名前を付けるかキーパターンを付けるかにかかわらず、同じように動作します。

    たとえば、コレクションにインデックス a_1、b_1、および fooがありa_1_b_1、インデックスリスト {query: {a: {$eq: "@"}, b: {$eq: "@"}}, sort: {a: 1}} を持つシェイプにフィルターを設定した場合["a_1", "a_1_b_1"]、 を実行すると db.foo.find({ a: 10, b: 20 }).sort({a: 1}).hint({ a: 1 })が使用されます。これはa_1、ヒントで名前が付けられ、フィルターで許可されているためです。

  • インデックスを削除しても、フィルターは変更されません。フィルターはインデックス名を保持します。そのインデックスが欠落している間、計画ではスキップされます。フィルターのリスト内の別のインデックスがクエリを処理できる場合でも、フィルターは引き続き適用されます。名前付きインデックスが利用できない場合にのみ、 がindexFilterAppliedレポートしますfalse。同じ名前のインデックスを再作成すると、再び対象になります。

  • コレクションを削除すると、そのコレクションのフィルターがすべて削除されます。