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