查询执行参考

本页面介绍了使用查询解释执行的查询的输出。如需了解如何使用查询解释执行查询,请参阅使用查询解释分析查询执行情况

常见概念

整个执行树中使用了以下常见概念和术语。

行和记录

术语记录用于泛指文档或索引条目。

变量

$ 表示在执行树中创建或引用的变量。例如:$foo_1。这些变量通常用于引用文档的内容或在查询执行期间评估的表达式的值。

以下内部变量可以出现在执行节点中:

  • $__key__ - 此键是文档的内部标识符。这是一个绝对的唯一标识符,其中包含项目、数据库和文档的完整路径。
  • $__id__ - 此 ID 是相应集合中某个文档的唯一标识符。这在单个集合中是唯一的。
  • $rid - 此行 ID 是存储空间中某个文档的内部标识符。这在单个集合中是唯一的。

以一个示例为例,其中使用 Compute 节点从文档 __key__ 计算 __id__

Compute | $__id__1: _id($__key__) | records returned: 1 

限制条件和范围

某些扫描节点使用 constraintsranges 属性来描述扫描的值范围。这些属性使用包含值列表的范围树格式。这些值与索引定义中显示的键的有序列表对应。例如,树中显示的第一个范围(此处为 (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

表示一种动态扫描,其中返回的行可能不在索引的单个连续范围内,并且必须执行多次不同的扫描才能满足查询。

例如,如果查询中存在 ab 等于 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_iddate_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

对集合进行无序的完整扫描。在运行没有关联索引的查询时使用。

顺序可以是 STABLEUNDEFINED,其中 STABLE 表示确定性排序。

• TableScan | order: STABLE | properties: * | records returned: 1 | records scanned: 1 | source: (default)#/**/collection 

应用

此操作会在两组数据(inputmap)之间执行联接。它会迭代 input 的每一行,并针对每一行扫描 map 端的数据并返回结果。

join_type 表示联接类型。例如,LEFT_OUTER 表示 input 中的所有行都将至少在输出中包含一次。如果 input 行在 map 端未找到任何匹配结果,系统仍会包含该行,但 map 端对应列的值将为 null

• Apply | join_type: LEFT_OUTER | └── • input tree | ... └── • map 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