本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
Amazon DocumentDB 中的查询
本节介绍使用 Amazon DocumentDB 进行查询的所有方面。
查询文档
有时,您可能需要查看在线商店的库存,这样客户就能看到并购买您销售的物品。查询集合相对容易,无论您想要集合中的所有文档,还是仅需要那些满足特定标准的文档。
要查询文档,请使用 find()
操作。find()
命令具有单个文档参数,该参数定义了在选择要返回的文档时要使用的标准。find()
的输出是一个文档,其格式为一行文本,不含换行符。要格式化输出文档,从而更加轻松地读取,请使用 find().pretty()
。本主题中的所有示例都使用 .pretty()
设置输出的格式。
下面的代码示例使用在前面两个练习中插入到 example
集合中的四个文档 — insertOne()
和 insertMany()
,它们位于使用文档的添加文档部分。
检索集合中的所有文档
要检索集合中的所有文档,请将 find()
操作和空查询文档结合使用。
以下查询返回 example
集合中的所有文档。
db.example.find( {} ).pretty()
检索与字段值匹配的文档
要检索与字段和值匹配的所有文档,请将 find()
操作和查询文档(标识要匹配的字段和值)结合使用。
通过使用前述文档,此查询将返回其中“Item”字段等于“Pen”的所有文档。
db.example.find( { "Item": "Pen" } ).pretty()
检索与嵌入文档匹配的文档
要查找与嵌入文档匹配的所有文档,请将 find()
操作和查询文档(指定嵌入文档名称和嵌入文档的所有字段和值)结合使用。
在与嵌入文档匹配时,该文档的嵌入文档的名称必须与查询中的名称相同。此外,嵌入文档中的字段和值必须与查询匹配。
以下查询仅返回“Poster Paint”文档。这是因为“Pen”具有不同的“OnHand
”和“MinOnHand
”值,并且“Spray Paint”比查询文档多一个字段 (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()
上述操作将返回所有三个文档,因为它们都有一个名为 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。因此,查询计划和 explain()
的输出在 Amazon DocumentDB 和 MongoDB 之间可能有所不同。希望控制其查询计划的客户可以使用 $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
结果。
扫描和过滤阶段
优化器可以选择以下扫描之一:
COLLSCAN
此阶段是顺序收集扫描。
{ "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
阶段和 $or
运算符的 inputStages
数组。
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 }
的复合索引可以支持以下所有三个查询:
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 支持两种不同的组策略:
SORT_AGGREGATE
:在磁盘上对聚合进行排序。HASH_AGGREGATE
: 在内存中对聚合进行哈希。