Amazon DocumentDB でのクエリの概要
このセクションでは、Amazon DocumentDB でのクエリのすべての側面について説明します。
ドキュメントのクエリ
ときどきオンラインストアのインベントリを検索し、販売商品を顧客が表示して購入できることを確認する必要があります。コレクションのクエリは、コレクションのすべてのドキュメントを対象とするか、特定の条件を満たすドキュメントのみを対象とするかにかかわらず、比較的簡単です。
ドキュメントのクエリを実行するには、find()
オペレーションを使用します。この find()
コマンドには、返すドキュメントを選択するために使用する条件を定義する単一のドキュメントパラメータがあります。find()
からの出力は、改行のない 1 行のテキストとしてフォーマットされたドキュメントです。読みやすくするために出力ドキュメントをフォーマットするには、find().pretty()
を使用します。このトピックのすべての例では、.pretty()
を使用して出力を書式設定しています。
以下のコードサンプルでは「Working with Documents」の「Adding Documents」セクションにある、前の 2 つの練習問題 - example
と insertOne()
で insertMany()
コレクションに挿入した 4 つのドキュメントを使用します。
コレクション内のすべてのドキュメントの取得
コレクション内のすべてのドキュメントを取得するには、find()
オペレーションで、空のクエリドキュメントを指定します。
以下のクエリは、example
コレクション内のすべてのドキュメントを返します。
db.example.find( {} ).pretty()
フィールドの値に一致するドキュメントの取得
フィールドおよび値に一致するすべてのドキュメントを取得するには、find()
オペレーションで、一致するフィールドおよび値を識別するクエリドキュメントを指定します。
上記のドキュメントを使用して、このクエリは、「Item」フィールドが「Pen」に等しいすべてのドキュメントを返します。
db.example.find( { "Item": "Pen" } ).pretty()
埋め込みドキュメントに一致するドキュメントの取得
埋め込みドキュメントに一致するすべてのドキュメントを検索するには、find()
オペレーションで、埋め込みドキュメントの名前と、その埋め込みドキュメントのすべてのフィールドおよび値を識別するクエリドキュメントを指定します。
埋め込みドキュメントに一致するには、そのドキュメントの埋め込みドキュメントの名前が、クエリで指定した名前と同じであることが必要です。さらに、埋め込みドキュメントのフィールドおよび値も、クエリで指定したものと同じであることが必要です。
次のクエリでは、「Poster Paint」ドキュメントのみ返ります。これは、「Pen」の値は「OnHand
」や「MinOnHand
」とは異なり、「Spray Paint」には、クエリドキュメントよりもフィールドが 1 つ (OrderQnty
) 多いためです。
db.example.find({"Inventory": { "OnHand": 47, "MinOnHand": 50 } } ).pretty()
埋め込まれたドキュメントのフィールド値に一致するドキュメントの取得
埋め込みドキュメントに一致するすべてのドキュメントを検索するには、find()
オペレーションで、埋め込みドキュメントの名前と、その埋め込みドキュメントのすべてのフィールドおよび値を識別するクエリドキュメントを指定します。
上記のドキュメントでは、以下のようにクエリで「ドット表記」を使用して埋め込みドキュメントと目的のフィールドを指定しています。埋め込みドキュメント内に他のフィールドがある場合でも、これらに一致するすべてのドキュメントが返されます。クエリは「Poster Paint」と「Spray Paint」を返します。それらはいずれも、指定したフィールドおよび値と一致するためです。
db.example.find({"Inventory.OnHand": 47, "Inventory.MinOnHand": 50 }).pretty()
配列に一致するドキュメントの取得
配列に一致するすべてのドキュメントを検索するには、find()
オペレーションで、目的の配列名とその配列内のすべての値を指定します。クエリは、配列値の名前および順序がクエリで指定したものと一致するすべてのドキュメントを返します。
以下のクエリは「Pen」のみを返します。「Poster Paint」では追加の色 (White) があり、「Spray Paint」では色の順序が異なるためです。
db.example.find( { "Colors": ["Red","Green","Blue","Black"] } ).pretty()
配列値に一致するドキュメントの取得
特定の属性配列を含むすべてのドキュメントを見つけるには、find()
オペレーションで、目的の配列名と値を指定します。
db.example.find( { "Colors": "Red" } ).pretty()
上記のオペレーションは、すべてのドキュメントを返します。3 つのドキュメントのそれぞれで、Colors
という配列があり、その配列のどこかに「Red
」という値があるためです。値として「White
」を指定すると、クエリからは「Poster Paint」のみが返されます。
演算子を使用したドキュメントの取得
以下のクエリは、「Inventory.OnHand
」値が 50 未満のすべてのドキュメントを返します。
db.example.find( { "Inventory.OnHand": { $lt: 50 } } )
サポートされているクエリ演算子のリストについては、「クエリおよびプロジェクション演算子」を参照してください。
クエリプラン
クエリプランの executionStats
を表示する方法を教えてください。
クエリの実行速度が予想よりも遅い理由を判断する場合は、クエリプランの executionStats
の目的を理解しておくと役立ちます。executionStats
は、特定のステージから返されたドキュメントの数 (nReturned
)、各ステージで費やされた実行時間 (executionTimeMillisEstimate
)、およびクエリプランの生成に要する時間 (planningTimeMillis
) を提供します。次のクエリ例に示すように、executionStats
の出力から、最も時間がかかるクエリ内のステージを判断して最適化作業を集中させることができます。executionStats
パラメータは、現在 update
コマンドと delete
コマンドをサポートしていません。
注記
Amazon DocumentDB は、分散型で、耐障害性が高く、自己復旧ストレージシステムを利用する専用データベースエンジンで MongoDB 3.6 API をエミュレートしています。その結果、Amazon DocumentDB と MongoDB では、クエリプランと explain()
の出力が異なる場合があります。クエリプランを制御する場合は、$hint
演算子を使用して優先インデックスの選択を強制できます。
次のように、explain()
コマンドで改善対象のクエリを実行します。
db.runCommand({explain: {query document}}). explain("executionStats").executionStats;
以下に示しているのは、オペレーションの例です。
db.fish.find({}).limit(2).explain("executionStats");
このオペレーションによる出力は、次のようになります。
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.fish",
"winningPlan" : {
"stage" : "SUBSCAN",
"inputStage" : {
"stage" : "LIMIT_SKIP",
"inputStage" : {
"stage" : "COLLSCAN"
}
}
}
},
"executionStats" : {
"executionSuccess" : true,
"executionTimeMillis" : "0.063",
"planningTimeMillis" : "0.040",
"executionStages" : {
"stage" : "SUBSCAN",
"nReturned" : "2",
"executionTimeMillisEstimate" : "0.012",
"inputStage" : {
"stage" : "LIMIT_SKIP",
"nReturned" : "2",
"executionTimeMillisEstimate" : "0.005",
"inputStage" : {
"stage" : "COLLSCAN",
"nReturned" : "2",
"executionTimeMillisEstimate" : "0.005"
}
}
}
},
"serverInfo" : {
"host" : "enginedemo",
"port" : 27017,
"version" : "3.6.0"
},
"ok" : 1
}
上のクエリの executionStats
のみを表示する場合は、次のコマンドを使用できます。小規模なコレクションで、パフォーマンスの向上がごくわずかである場合、Amazon DocumentDB クエリプロセッサはインデックスを使用しないことがあります。
db.fish.find({}).limit(2).explain("executionStats").executionStats;
クエリプランキャッシュ
パフォーマンスを最適化し、計画期間を短縮するために、Amazon DocumentDB はクエリプランを内部的にキャッシュしています。これにより、同じ形状のクエリは、キャッシュされたプランを使用して直接実行することができます。
ただし、このキャッシュにより、同じクエリでもランダムに遅延が発生することがあります。例えば、通常 1 秒で実行されるクエリが、時には 10 秒かかることがあります。これは、時間の経過とともに、リーダーインスタンスがクエリのさまざまな形状をキャッシュし、メモリを消費するためです。このランダムな速度低下が発生した場合、メモリを解放するために必要なアクションはありません。システムがメモリ使用量を管理し、メモリが一定のしきい値に達すると、自動的に解放されます。
結果の説明
Amazon DocumentDB は、クエリプランに関する情報を返すために、冗長モード queryPlanner
をサポートしています。explain
の結果は、オプティマイザによって選択されたクエリプランを、以下のような形式で返します。
{ "queryPlanner" : { "plannerVersion" : <int>, "namespace" : <string>, "winningPlan" : { "stage" : <STAGE1>, ... "inputStage" : { "stage" : <STAGE2>, ... "inputStage" : { ... } } } } }
以下のセクションでは、一般的な explain
の結果を定義します。
スキャンとフィルタのステージ
オプティマイザは、以下のいずれかのスキャンのいずれかを選択します。
COLSCAN
このステージは、順次収集スキャンです。
{ "stage" : "COLLSCAN" }
IXSCAN
このステージでは、インデックスキーをスキャンします。オプティマイザはこのステージ内でドキュメントを取得することがあり、その結果、後で FETCH ステージが追加されることがあります。
db.foo.find({"a": 1}) { "stage" : "IXSCAN", "direction" : "forward", "indexName" : <idx_name> }
FETCH
オプティマイザが IXSCAN 以外のステージでドキュメントを取得した場合、その結果には FETCH ステージが含まれます。例えば、上記の IXSCAN クエリは、FETCH と IXSCAN ステージを組み合わせた結果になる可能性があります。
db.foo.find({"a": 1}) { "stage" : "FETCH", "inputStage" : { "stage" : "IXSCAN", "indexName" : <idx_name> } }
IXONLYSCAN はインデックスキーのみをスキャンします。複合インデックスを作成しても、FETCH は回避されません。
インデックス公差
IXAND
Amazon DocumentDB は、インデックス交差を利用できる場合、IXSCAN の InputStages 配列を持つ IXAND ステージを含めることができます。例えば、次のような出力が表示される場合があります。
{ "stage" : "FETCH", "inputStage" : { "stage" : "IXAND", "inputStages" : [ { "stage" : "IXSCAN", "indexName" : "a_1" }, { "stage" : "IXSCAN", "indexName" : "b_1" } ] } }
インデックス結合
IXOR
インデックス交差と同様に、Amazon DocumentDBは、IXOR
演算子の inputStages
配列で $or
ステージを含むことができます。
db.foo.find({"$or": [{"a": {"$gt": 2}}, {"b": {"$lt": 2}}]})
上記のクエリの場合、説明出力は以下のようになります。
{ "stage" : "FETCH", "inputStage" : { "stage" : "IXOR", "inputStages" : [ { "stage" : "IXSCAN", "indexName" : "a_1" }, { "stage" : "IXSCAN", "indexName" : "b_1" } ] } }
複数のインデックス交差/結合
Amazon DocumentDB は、複数のインデックス交差または結合ステージを組み合わせて、結果を取得できます。例:
{ "stage" : "FETCH", "inputStage" : { "stage" : "IXOR", "inputStages" : [ { "stage" : "IXSCAN", ... }, { "stage" : "IXAND", "inputStages" : [ { "stage" : "IXSCAN", ... }, { "stage" : "IXSCAN", ... } ] } ] } }
インデックスの交差や結合ステージの使用は、インデックスの種類(スパース、複合など)に影響されません。
複合インデックス
Amazon DocumentDB の複合インデックスの使用は、インデックスされたフィールドの最初のサブセットに限定されるものではありません。それはサフィックス部分を持つインデックスを使用できますが、あまり効率的ではないかもしれません。
例えば、{ a: 1, b: -1 }
の複合インデックスは、以下の 3 つのクエリをサポートすることができます。
db.orders.find( { a: 1 } } )
db.orders.find( { b: 1 } } )
db.orders.find( { a: 1, b: 1 } } )
ソートステージ
要求されたソートキーにインデックスがある場合、Amazon DocumentDB はインデックスを使用して順序を取得することができます。その場合、結果には SORT
ステージではなく IXSCAN
ステージが含まれます。オプティマイザがプレーンソートを好む場合は、次のようなステージが含まれます。
{ "stage" : "SORT", "sortPattern" : { "a" : 1, "b" : -1 } }
グループステージ
Amazon DocumentDBは、2 つの異なるグループ戦略をサポートしています。
SORT_AGGREGATE
: オンディスクソート集計。HASH_AGGREGATE
: メモリハッシュ集計。