查询执行参考
本页面介绍了使用查询解释执行的查询的输出。如需了解如何使用查询解释执行查询,请参阅使用查询解释分析查询执行情况。
常见概念
整个执行树中使用了以下常见概念和术语。
行和记录
术语行和记录用于泛指文档或索引条目。
变量
$
表示在执行树中创建或引用的变量。例如:$foo_1
。这些变量通常用于引用文档的内容或在查询执行期间评估的表达式的值。
以下内部变量可以出现在执行节点中:
$__key__
- 此键是文档的内部标识符。这是一个绝对的唯一标识符,其中包含项目、数据库和文档的完整路径。$__id__
- 此 ID 是相应集合中某个文档的唯一标识符。这在单个集合中是唯一的。$rid
- 行 ID 是存储空间中某个文档的内部标识符。 这在单个集合中是唯一的。
以一个示例为例,其中使用 Compute
节点从文档 __key__
计算 __id__
:
Compute
| $__id__1: _id($__key__)
| records returned: 1
限制条件和范围
某些扫描节点使用 constraints
和 ranges
属性来描述扫描的值范围。这些属性使用包含值列表的范围树格式。这些值与索引定义中显示的键的有序列表对应。例如,树中显示的第一个范围(此处为 (1..5]
)与键的有序列表中第一个键(此处为 a
)的限制条件对应:
| index: type=CollectionGroupIndex, id=CICAgOjXh#EK, keys=[a ASC, b ASC, __key__ ASC]
| constraints: /
|----(1..5]
|----[1L]
每个缩进级别都表示适用于列表中下一个键的限制条件。方括号表示包含范围,圆括号表示不含范围。在这种情况下,限制条件会转换为 1 < "a" <= 5
和 "b" = 1
。
在以下示例中,a
有多个分支,限制条件对应于 1 < a <= 5 OR a = 10
:
| constraints: /
|----(1L, 5L]
|----[10L]
键变量
在某些扫描节点(例如 SequentialScan
)中,index
属性中包含一个键列表,且 Scan
节点中包含一个单独的 keys
属性。Scan
节点中的 keys
属性按顺序表示索引定义中每个键的变量名称。这些变量可用于引用执行树中扫描字段的运行时值。
在以下示例中,当前文档的 user
字段的值会映射到变量 $user_1
,而 date_placed
的值会映射到 $date_placed_1
。
index: type=CollectionGroupIndex, id=CICAgOjXh4EK, keys=[user ASC, date_placed ASC, __key__ ASC]
keys: [user ASC, date_placed ASC, __key__ ASC]
执行节点
查询执行树可以包含以下节点。
SeekingScan
表示一种动态扫描,其中返回的行可能不在索引的单个连续范围内,并且必须执行多次不同的扫描才能满足查询。
例如,如果查询中存在 a
且 b
等于 1,并且查询针对 ["a" ASC, "b" ASC]
的索引运行,则需要扫描并返回 a
的每个不同值的单独范围(可能不是连续范围)。这比完整的 TableScan
更高效,但不如在 ["b" ASC, "a" ASC]
的复合索引上使用单个 SequentialScan
高效。
• SeekingScan
| constraints: /
|----(-∞..+∞)
|----[1L]
| index: type=CollectionGroupIndex, id=CAE, keys=[user ASC, quantity ASC, __key__ ASC]
| keys: [user ASC, quantity ASC, __key__ ASC]
| properties: Selection { user }
| records returned: 1
| records scanned: 1
SequentialScan
表示对存储空间中静态的连续行范围的扫描,该扫描可在单次读取操作中执行。
key ordering length
是指必须保留并按原始键顺序返回的键的数量。对于 [k1, k2, k3]
的架构,键排序长度为 0 表示扫描可以按任意顺序返回,1 表示按 k1 排序,但具有相同 k1 值的行可以按任意顺序返回,3 表示按精确的排列顺序返回文档。
• SequentialScan
| index: type=CollectionGroupIndex, id=CAE, keys=[user ASC, date_placed ASC, __key__ ASC]
| key ordering length: 3
| keys: [user ASC, date_placed ASC, __key__ ASC]
| limit: 10
| properties: Selection { a }
| ranges: /
| records returned: 1
| records scanned: 1
UniqueScan
表示对存储空间中静态的连续行范围进行扫描,并对行进行内存重复数据删除。
• UniqueScan
| index: type=CollectionGroupIndex, id=CAE, keys=[user ASC, date_placed ASC, __key__ ASC]
| keys: [user ASC, date_placed ASC, __key__ ASC]
| properties: Selection { a }
| ranges: /
|----(-∞..+∞)
| records returned: 1
| records scanned: 1
IndexSeek
表示一种动态扫描,其中返回的行可能由运行时数据进行形参化,并且可能不在索引的单个连续范围内,并且可能执行多次不同的扫描才能满足查询。
例如,如果查询中 user
等于 $user_id
且 date_placed
等于 "2025-08-10"
,并且查询针对 ["user" ASC, "date_placed" ASC]
的索引运行,则会在运行时使用 $user_id
变量的值,并使用 date_placed
的 "2025-08-10"
限制来限制扫描范围。
• IndexSeek
| index: type=CollectionGroupIndex, id=CAE, keys=[user ASC, date_placed ASC, __key__ ASC]
| fields: [$user_1 ASC, $date_placed_1 ASC, $rid ASC]
| key: $key_1
| filter: $eq($user_1, $user_id) AND $eq($date_placed_1, "2025-08-10")
| records returned: 1
| records scanned: 1
TableAccess
将所提供行的标识符与来自主要存储空间的实际行内容进行反向联接。如果父节点(或最终查询结果)需要文档中的部分字段,则必须使用 TableAccess
。
• TableAccess
| order: PRESERVE_INPUT_ORDER
| peak memory usage: 4.00 KiB (4,096 B)
| properties: *
| records returned: 1
LookupById
通过按 ID 查找外部集合中的文档来执行联接。要查找的 ID 源自输入文档中的某个字段。查找结果会作为新字段添加到输入文档。
• LookupById
| local_field: $localField_1
| foreign_datasource: (default)#/**/foreign
| output: $output_1
TableScan
对集合进行无序的完整扫描。在运行没有关联索引的查询时使用。
顺序可以是 STABLE
或 UNDEFINED
,其中 STABLE
表示确定性排序。
• TableScan
| order: STABLE
| properties: *
| records returned: 1
| records scanned: 1
| source: (default)#/**/collection
NestedLoopJoin
通过以下方式在两组数据(左侧和右侧)之间执行联接:遍历左侧输入的每一行,并针对每个左侧行,根据 join_condition
扫描右侧输入以查找匹配的行。
join_type
表示联接类型。例如,LEFT_OUTER
表示左侧输入中的所有行至少在输出中出现一次。如果左侧行根据 join_condition
与右侧输入中的任何行都不匹配,则仍会包含该行,但右侧输入中的列会显示 null 值。
• NestedLoopJoin
| join_type: LEFT_OUTER
| join_condition: $eq($left, $right)
|
└── • left tree
| ...
└── • right tree
...
HashAggregate
哈希支持的聚合操作实现。需要在内存中具体化整个群组,然后才能返回结果,并且不得超过查询内存限制。
• HashAggregate
| aggregations: [sum($b_1) AS total]
| groups: [$a_1]
| peak memory usage: 4.00 KiB (4,096 B)
| records returned: 0
StreamAggregate
一种专门的聚合节点,一次只维护一个组的状态,从而减少内存用量峰值。当底层子节点按顺序返回组时使用。例如,当按字段的不同值进行分组时,同时在该字段上使用索引。
• StreamAggregate
| keys: [foo ASC, bar ASC]
| properties: Selection { baz }
| aggregations: [$sum($foo_1) AS baz]
MajorSort
对一组固定的属性执行排序操作。一次性将所有记录具体化到内存中,并按顺序返回排序后的值,排序集的大小受查询内存限制的限制。
如果提供了后续限制,系统会使用 top-k 排序算法来减少内存用量。借助此方法,可以对任意大的记录集执行排序,只要存储所考虑的 k 个元素的内存不超过限制即可。
• MajorSort
| fields: [a ASC, b DESC]
| limit: 10
| peak memory usage: 4.00 KiB (4,096 B)
| records returned: 1
Concat
串联多个子节点的结果,并将结果返回到父节点。此节点不会对多个子节点中显示的结果进行去重,且返回结果的顺序是不确定的。
• Concat
├── • TableAccess
...
├── • TableAccess
计算
对一组表达式求值,并将结果分配给一组变量。
• Compute
| $user_1: user
| $full_name_1: str_concat($first_name_1, " ", $last_name_1)
| $address_1: UNSET
| records returned: 1
过滤
仅当行与提供的表达式匹配时,才选择性地返回这些行。
• Filter
| expression: $eq(foo, "bar")
| records returned: 1
RecordCount
统计子节点生成的行数,并将当前统计结果输出到 count
属性中指定的变量。
• RecordCount
| count: $row_number_1
| records returned: 1
值
生成要处理的一系列字面量值。主要在提供一组文档列表作为查询的输入时使用。
• Values
| expression: [{__key__=/col/1}, {__key__=/col/2}]
Unnest
取消嵌套子节点生成的值。
• Unnest
| expression: foo AS unnested_foo
限制
限制返回到父节点的行数。
• Limit
| limit: 10
| records returned: 1
偏移
跳过子节点生成的一定数量的行。
• Offset
| offset: 10
| records returned: 1