Referencia de ejecución de consultas
En esta página se explica el resultado de una consulta ejecutada con Query Explain. Para saber cómo ejecutar una consulta con Query Explain, consulta Analizar la ejecución de consultas con Query Explain.
Conceptos habituales
Los siguientes conceptos y términos comunes se usan en todo el árbol de ejecución.
Filas y registros
Los términos fila y registro se usan para hacer referencia de forma genérica a un documento o a una entrada de índice.
Variables
$
denota una variable que se crea o
a la que se hace referencia en el árbol de ejecución. Por ejemplo: $foo_1
. Estas variables se suelen usar para hacer referencia al contenido de un documento o al valor de una expresión evaluada durante la ejecución de una consulta.
Las siguientes variables internas pueden aparecer en los nodos de ejecución:
$__key__
: la clave es un identificador interno de un documento. Se trata de un identificador absoluto y único del proyecto, la base de datos y la ruta completa del documento.$__id__
: el ID es un identificador único de un documento dentro de su colección. Es único en una sola colección.$rid
: el ID de fila es un identificador interno de un documento almacenado. Es único en una sola colección.
Veamos un ejemplo en el que se usa un nodo Compute
para calcular el __id__
del documento __key__
:
Compute
| $__id__1: _id($__key__)
| records returned: 1
Restricciones e intervalos
Algunos nodos de análisis usan los atributos constraints
y ranges
para describir el intervalo de valores que se analizan. Estos atributos usan un formato de árbol de intervalos que contiene una lista de valores. Estos valores se corresponden con la lista ordenada de claves que aparecen en la definición del índice. Por ejemplo, el primer intervalo que aparece en el árbol, (1..5]
, corresponde a las restricciones de la primera clave, a
, en la lista ordenada de claves:
| index: type=CollectionGroupIndex, id=CICAgOjXh#EK, keys=[a ASC, b ASC, __key__ ASC]
| constraints: /
|----(1..5]
|----[1L]
Cada nivel de sangría indica la restricción que se aplica a la siguiente clave de la lista. Los corchetes representan un intervalo inclusivo y los paréntesis, un intervalo exclusivo. En este caso, la restricción se traduce en 1 < "a" <= 5
y "b" = 1
.
En el siguiente ejemplo con varias ramas para a
, la restricción corresponde a 1 < a <= 5 OR a = 10
:
| constraints: /
|----(1L, 5L]
|----[10L]
Variables clave
En algunos nodos de análisis (como SequentialScan
), hay una lista de claves como parte del atributo index
y un atributo keys
independiente en el nodo Scan
. El atributo keys
del nodo Scan
indica el nombre de la variable de cada clave de la definición del índice, por orden. Las variables se pueden usar para hacer referencia a los valores de tiempo de ejecución del campo analizado más arriba en el árbol de ejecución.
En el ejemplo siguiente, el valor del campo user
del documento actual se asigna a la variable $user_1
y el valor de date_placed
a $date_placed_1
.
index: type=CollectionGroupIndex, id=CICAgOjXh4EK, keys=[user ASC, date_placed ASC, __key__ ASC]
keys: [user ASC, date_placed ASC, __key__ ASC]
Nodos de ejecución
Un árbol de ejecución de consultas puede contener los siguientes nodos.
SeekingScan
Representa un análisis dinámico en el que las filas devueltas pueden no estar en un único intervalo secuencial del índice y se deben realizar varios análisis distintos para satisfacer la consulta.
Por ejemplo, una consulta en la que a
existe y b
es igual a 1 en un índice de ["a" ASC, "b" ASC]
tendría que analizar y devolver un intervalo independiente, posiblemente no secuencial, para cada valor distinto de a
.
Es más eficiente que un TableScan
completo, pero menos eficiente que un solo SequentialScan
en un índice compuesto de ["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: 1
SequentialScan
Representa un análisis de un intervalo estático y secuencial de filas en el almacenamiento que se puede realizar en una sola operación de lectura.
key ordering length
hace referencia al número de claves que se deben conservar y devolver en el orden original de las claves. En un esquema de [k1, k2, k3]
, una longitud de ordenación de claves de 0 significa que la lectura puede devolver los resultados en cualquier orden, 1 significa que se ordenan por k1, pero las filas con el mismo valor de k1 pueden aparecer en cualquier orden, y 3 devuelve los documentos en el orden exacto.
• 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
Representa un análisis de un intervalo estático y secuencial de filas en el almacenamiento con deduplicación de filas en memoria.
• 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
Representa un análisis dinámico en el que las filas devueltas se pueden parametrizar con datos de tiempo de ejecución y puede que no se encuentren en un único intervalo secuencial del índice. Además, se pueden realizar varios análisis distintos para satisfacer la consulta.
Por ejemplo, una consulta en la que user
es igual a $user_id
y date_placed
es igual a "2025-08-10"
que se ejecuta en un índice de ["user" ASC, "date_placed" ASC]
usaría el valor de la variable $user_id
en el tiempo de ejecución y la restricción "2025-08-10"
en date_placed
para limitar los intervalos de análisis.
• 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
Vuelve a unir el identificador de la fila proporcionada al contenido real de la fila del almacenamiento principal. TableAccess
es obligatorio si un nodo principal (o el resultado de la consulta final) requiere un subconjunto de campos de los documentos.
• TableAccess
| order: PRESERVE_INPUT_ORDER
| peak memory usage: 4.00 KiB (4,096 B)
| properties: *
| records returned: 1
LookupById
Realiza una unión buscando documentos en una colección externa por su ID. Los IDs que se van a buscar se obtienen de un campo de los documentos de entrada. Los resultados de la búsqueda se añaden como un nuevo campo a los documentos de entrada.
• LookupById
| local_field: $localField_1
| foreign_datasource: (default)#/**/foreign
| output: $output_1
TableScan
Un análisis completo y desordenado de una colección. Se usa cuando se ejecuta una consulta sin un índice asociado.
El orden puede ser STABLE
o UNDEFINED
. STABLE
indica un orden determinista.
• TableScan
| order: STABLE
| properties: *
| records returned: 1
| records scanned: 1
| source: (default)#/**/collection
NestedLoopJoin
Realiza una combinación entre dos conjuntos de datos (izquierdo y derecho) iterando por cada fila de la entrada de la izquierda y, por cada fila de la izquierda, buscando en la entrada de la derecha las filas coincidentes en función de join_condition
.
El join_type
indica el tipo de unión. Por ejemplo, LEFT_OUTER
significa que todas las filas de la entrada de la izquierda se incluyen al menos una vez en la salida.
Si una fila de la izquierda no coincide con ninguna fila de la entrada de la derecha según la join_condition
, se incluirá igualmente, pero con valores nulos en las columnas de la entrada de la derecha.
• NestedLoopJoin
| join_type: LEFT_OUTER
| join_condition: $eq($left, $right)
|
└── • left tree
| ...
└── • right tree
...
HashAggregate
Implementación de operaciones de agregación basada en hash. Requiere materializar todo el grupo en la memoria antes de devolver el resultado y no debe superar el límite de memoria de la consulta.
• HashAggregate
| aggregations: [sum($b_1) AS total]
| groups: [$a_1]
| peak memory usage: 4.00 KiB (4,096 B)
| records returned: 0
StreamAggregate
Nodo agregado especializado que solo mantiene el estado de un grupo a la vez, lo que reduce el uso máximo de memoria. Se usa cuando el nodo secundario subyacente devuelve grupos de forma secuencial. Por ejemplo, al agrupar por valores distintos de un campo mientras se usa un índice en ese campo.
• StreamAggregate
| keys: [foo ASC, bar ASC]
| properties: Selection { baz }
| aggregations: [$sum($foo_1) AS baz]
MajorSort
Realiza una operación de ordenación en un conjunto fijo de propiedades. Materializa todos los registros en la memoria a la vez y devuelve los valores ordenados. El tamaño del conjunto de ordenación está limitado por el límite de memoria de la consulta.
Cuando se proporciona un límite posterior, se usa un algoritmo de ordenación de los k elementos principales para reducir el uso de memoria. Con él, las ordenaciones se pueden realizar en un conjunto de registros arbitrariamente grande siempre que la memoria utilizada para almacenar los elementos considerados no supere el límite.
• MajorSort
| fields: [a ASC, b DESC]
| limit: 10
| peak memory usage: 4.00 KiB (4,096 B)
| records returned: 1
Concat
Concatena los resultados de varios nodos secundarios y devuelve el resultado al nodo principal. Este nodo no elimina los resultados duplicados que aparecen en varios elementos secundarios y el orden de los resultados devueltos no es determinista.
• Concat
├── • TableAccess
...
├── • TableAccess
Computación
Evalúa un conjunto de expresiones y asigna los resultados a un conjunto de variables.
• Compute
| $user_1: user
| $full_name_1: str_concat($first_name_1, " ", $last_name_1)
| $address_1: UNSET
| records returned: 1
Filtro
Devuelve filas de forma selectiva si y solo si coinciden con la expresión proporcionada.
• Filter
| expression: $eq(foo, "bar")
| records returned: 1
RecordCount
Cuenta el número de filas que genera el nodo secundario y emite el recuento actual a la variable especificada en el atributo count
.
• RecordCount
| count: $row_number_1
| records returned: 1
Valores
Genera una secuencia de valores literales con los que trabajar. Se usa principalmente cuando se proporciona un conjunto o una lista de documentos como entrada de una consulta.
• Values
| expression: [{__key__=/col/1}, {__key__=/col/2}]
Desanidar
Desanida el valor producido por el nodo secundario.
• Unnest
| expression: foo AS unnested_foo
Límite
Limita el número de filas devueltas al nodo principal.
• Limit
| limit: 10
| records returned: 1
Desplazamiento
Omite un número determinado de filas generadas por el nodo secundario.
• Offset
| offset: 10
| records returned: 1