Query execution reference Stay organized with collections Save and categorize content based on your preferences.
This page explains the output of a query executed with Query Explain.To learn how to execute a query with Query Explain, seeAnalyze query execution with Query Explain.
Common Concepts
The following common concepts and terms are used throughout theexecution tree.
Rows and records
The termsrow andrecord are used to generically refer to a document or index entry.
Variables
$ denotes a variable, which is created or referenced in the execution tree. For example:$foo_1. These variables are typically used to refer to the contents of a document or the value of an expression evaluated during the execution of a query.
The following internal variables can appear in the execution nodes:
$__key__- the key is an internal identifier for a document. This isan absolute, unique identifier with the project, database, and the full pathof the document.$__id__- the ID is a unique identifier for a document within its collection.This is unique within a single collection.$rid- the row ID is an internal identifier for a document in storage.This is unique within a single collection.
Consider an example where aCompute node is used to compute the__id__ from the document__key__:
Compute | $__id__1: _id($__key__) | records returned: 1Constraints and ranges
Some scan nodes useconstraints andranges attributes to describe the rangeof values that are scanned. These attributes use a range tree format whichcontains a list of values. These values correspond to the ordered list of keyswhich appear in the index definition. For example, the first range which appearsin the tree, here(1..5], corresponds to the constraints on the first key,herea, in the ordered list of keys:
| index: type=CollectionGroupIndex, id=CICAgOjXh#EK, keys=[a ASC, b ASC, __key__ ASC]| constraints: / |----(1..5] |----[1L]Each level of indentation indicates the constraint applying to the next key inthe list. Square brackets represent an inclusive range, rounded brackets are anexclusive range. In this case, the constraint translates to1 < "a" <= 5, and"b" = 1.
In the following example with multiple branches fora,the constraint corresponds to1 < a <= 5 OR a = 10:
| constraints: / |----(1L, 5L] |----[10L]Key Variables
In some scan nodes (such asSequentialScan), there is both a list of keys aspart of theindex attribute, and a separatekeys attribute in theScan node. Thekeys attribute in theScan node denotes the variable name of each key in theindex definition, in order. The variables can be used to reference the runtimevalues of the scanned field further up in the execution tree.
In the following example, the value of theuser field for the current documentmaps to variable$user_1 and the value ofdate_placed to$date_placed_1.
index: type=CollectionGroupIndex, id=CICAgOjXh4EK, keys=[user ASC, date_placed ASC, __key__ ASC]keys: [user ASC, date_placed ASC, __key__ ASC]Execution Nodes
A query execution tree can contain the following nodes.
SeekingScan
Represents a dynamic scan where the rows returned may not be along a singlesequential range of the index, and multiple distinct scans must be performed tosatisfy the query.
For example, a query wherea exists andb equals 1 working on anindex of["a" ASC, "b" ASC], would need to scan and return a separate,potentially non-sequential range for each distinct value ofa.This is more efficient than a fullTableScan, but less efficient than a singleSequentialScan on a composite index of["b" ASC, "a" ASC].
• 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: 1SequentialScan
Represents a scan of a static, sequential range of rows in storage that can beperformed in a single read operation.
Thekey ordering length refers to the number of keys that must be preservedand returned in original key order. For a schema of[k1, k2, k3], a keyordering length of 0 means the scan can return in any order, 1 means order byk1, but rows with the same k1 value can come with any order, 3 returns documentsin exact sorted order.
• 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: 1UniqueScan
Represents a scan of a static, sequential range of rows in storage within-memory deduplication of rows.
• 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: 1IndexSeek
Represents a dynamic scan where the rows returned may be parametrized by runtimedata and might not be along a single sequential range of the index, and multipledistinct scans may be performed to satisfy the query.
For example, a query whereuser equals$user_id anddate_placed equals"2025-08-10" running on an index of["user" ASC, "date_placed" ASC], woulduse the value of the$user_id variable at runtime and the"2025-08-10"constraint ondate_placed to restrict the scan ranges.
• 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: 1Fetch
Back-joins the supplied row's identifier to the actual row contents from primarystorage.Fetch is required if a parent node (or the final queryresult) requires a subset of fields from the documents.
• Fetch| order: PRESERVE_INPUT_ORDER| peak memory usage: 4.00 KiB (4,096 B)| properties: *| records returned: 1LookupById
Performs a join by looking up documents in a foreign collection by their ID. TheIDs to look up are sourced from a field in the input documents. The results ofthe lookup are added as a new field to the input documents.
• LookupById| local_field: $localField_1| foreign_datasource: (default)#/**/foreign| output: $output_1TableScan
A full, unordered scan of a collection. Used when a query is run without anassociated index.
Order can be eitherSTABLE orUNDEFINED, withSTABLE denoting adeterministic ordering.
• TableScan| order: STABLE| properties: *| records returned: 1| records scanned: 1| source: (default)#/**/collectionApply
Performs a join between two sets of data (input andmap) by iteratingthrough each row of theinput and, for each row, scanning and returningresults from themap side.
Thejoin_type indicates the type of join. For example,LEFT_OUTERmeans all rows from theinput are included at least once in the output.If aninput row does not find any results from themap side, it will stillbe included, withnull values for the columns from themap side.
• Apply| join_type: LEFT_OUTER|└── • input tree| ...└── • map tree ...HashAggregate
Hash-backed implementation of aggregate operations. Requires materializing thefull group in-memory before returning the result and must not exceed thethequery memory limit.
• HashAggregate| aggregations: [sum($b_1) AS total]| groups: [$a_1]| peak memory usage: 4.00 KiB (4,096 B)| records returned: 0StreamAggregate
Specialized aggregate node which only maintains state for a single group ata time, reducing peak memory usage. Used when the underlying child node willreturn groups sequentially. For example, when grouping by distinct values of afield while using an index on that field.
• StreamAggregate| keys: [foo ASC, bar ASC]| properties: Selection { baz }| aggregations: [$sum($foo_1) AS baz]MajorSort
Performs a sort operation on a fixed set of properties. Materializes all recordsin memory at once and returns the sorted values in order, the size of the sortset is limited by thequery memory limit.
When a subsequent limit is provided, a top-k sorting algorithm is used to reducethe memory usage. With it, sorts can be performed on an arbitrarily large set ofrecords so long as the memory used by storing the k considered elements does notexceed the limit.
• MajorSort| fields: [a ASC, b DESC]| limit: 10| peak memory usage: 4.00 KiB (4,096 B)| records returned: 1Concat
Concatenates the results of multiple child nodes and returns the result tothe parent node. This node does not deduplicate results that appear inmultiple children, and the order of returned results is nondeterministic.
• Concat├── • Fetch...├── • FetchCompute
Evaluates a set of expressions, assigning the results to a set of variables.
• Compute| $user_1: user| $full_name_1: str_concat($first_name_1, " ", $last_name_1)| $address_1: UNSET| records returned: 1Filter
Selectively returns rows if and only if they match the supplied expression.
• Filter| expression: $eq(foo, "bar")| records returned: 1RecordCount
Counts the number of rows produced by the child node and emits the current count to the variable specified in thecount attribute.
• RecordCount| count: $row_number_1| records returned: 1Values
Produces a sequence of literal values to work on. Used primarily when a setlist of documents is provided as the input to a query.
• Values| expression: [{__key__=/col/1}, {__key__=/col/2}]Unnest
Unnests the value produced by the child node.
• Unnest| expression: foo AS unnested_fooLimit
Limits the number of rows returned to the parent node.
• Limit| limit: 10| records returned: 1Offset
Skips a set number of rows produced by the child node.
• Offset| offset: 10| records returned: 1Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2026-02-18 UTC.