Comprender el rendimiento de las consultas con Explicación de consultas

La explicación de consultas te permite enviar consultas de Firestore al backend y recibir estadísticas de rendimiento detalladas sobre la ejecución de la consulta de backend. Funciona como la operación EXPLAIN [ANALYZE] en muchos sistemas de base de datos relacional.

Las solicitudes de explicación de consultas se pueden enviar mediante las bibliotecas cliente del servidor de Firestore.

Los resultados de la explicación de consultas te ayudan a comprender cómo se ejecutan las consultas y te muestran las ineficiencias y la ubicación de los probables cuellos de botella en el servidor.

Explicación de la consulta:

  • Proporciona estadísticas sobre la fase de planificación de consultas para que puedas ajustar tus índices de consulta y aumentar la eficiencia.
  • Usar la opción de análisis te ayuda a comprender el costo y el rendimiento por consulta y te permite iterar con rapidez por diferentes patrones de consulta para optimizar su uso.

Comprende las opciones de explicación de las consultas: predeterminadas y análisis

Las operaciones de explicación de consultas se pueden realizar con las opciones predeterminadas o analizar.

Con la opción predeterminada, Explicación de consulta planifica la consulta, pero omite la etapa de ejecución. Esto devolverá la información de la etapa del planificador. Puedes usar esta opción para verificar que una consulta tenga los índices necesarios y comprender cuáles se usan. Esto te ayudará a verificar, por ejemplo, que una consulta en particular use un índice compuesto en lugar de tener que cruzarse en muchos índices diferentes.

Con la opción de análisis, Query Explain planifica y ejecuta la consulta. Esto muestra toda la información de planificador mencionada anteriormente junto con las estadísticas del tiempo de ejecución de ejecución de la consulta. Esto incluirá los datos de facturación de la consulta junto con las estadísticas a nivel del sistema sobre la ejecución de la consulta. Puedes usar estas herramientas para probar varias configuraciones de índices y consultas a fin de optimizar su costo y latencia.

¿Cuánto cuesta una explicación de consultas?

Cuando usas Explicación de consultas con la opción predeterminada, no se realizan operaciones de índice ni de lectura. Sin importar la complejidad de la consulta, se cobra una operación de lectura.

Cuando usas Explicación de consultas con la opción de analizar, se realizan las operaciones de índice y de lectura, por lo que se te cobra por la consulta como de costumbre. No se aplican cargos adicionales por la actividad de análisis, solo el cargo habitual por la consulta que se ejecuta.

Usar Explicación de consulta con la opción predeterminada

Puedes usar las bibliotecas cliente para enviar una solicitud de opción predeterminada.

Ten en cuenta que las solicitudes se autentican con IAM y se usan los mismos permisos para las operaciones de consulta regulares. Se ignoran otras técnicas de autenticación, como Firebase Authentication. Si quieres obtener más información, consulta la guía sobre IAM para bibliotecas cliente del servidor.

Java (Administrador)

Query q = db.collection("col").whereGreaterThan("a", 1);
ExplainOptions options = ExplainOptions.builder().build();

ExplainResults<QuerySnapshot> explainResults = q.explain(options).get();
ExplainMetrics metrics = explainResults.getMetrics();
PlanSummary planSummary = metrics.getPlanSummary();

    
Nodo (administrador)

const q = db.collection('col').where('country', '=', 'USA');
const options = { analyze : 'false' };

const explainResults = await q.explain(options);

const metrics = explainResults.metrics;
const plan = metrics.planSummary;

    

El formato exacto de la respuesta depende del entorno de ejecución. Los resultados que se muestran se pueden convertir a JSON. Por ejemplo:

{
    "indexes_used": [
        {"query_scope": "Collection", "properties": "(category ASC, __name__ ASC)"},
        {"query_scope": "Collection", "properties": "(country ASC, __name__ ASC)"},
    ]
}

Para obtener más información, consulta la referencia del informe de explicación de consultas.

Usar Explicación de consultas con la opción de analizar

Puedes usar las bibliotecas cliente para enviar una solicitud de opción de análisis.

Ten en cuenta que las solicitudes se autentican con IAM y se usan los mismos permisos para las operaciones de consulta regulares. Se ignoran otras técnicas de autenticación, como Firebase Authentication. Si quieres obtener más información, consulta la guía sobre IAM para bibliotecas cliente del servidor.

Java (Administrador)

Query q = db.collection("col").whereGreaterThan("a", 1);

ExplainOptions options = ExplainOptions.builder().setAnalyze(true).build();

ExplainResults<QuerySnapshot> explainResults = q.explain(options).get();

ExplainMetrics metrics = explainResults.getMetrics();
PlanSummary planSummary = metrics.getPlanSummary();
List<Map<String, Object>> indexesUsed = planSummary.getIndexesUsed();
ExecutionStats stats = metrics.getExecutionStats();

    
Nodo (administrador)

const q = db.collection('col').where('country', '=', 'USA');

const options = { analyze : 'true' };

const explainResults = await q.explain(options);

const metrics = explainResults.metrics;
const plan = metrics.planSummary;
const indexesUsed = plan.indexesUsed;
const stats = metrics.executionStats;

    

En el siguiente ejemplo, se muestra el objeto stats que se muestra además de planInfo. El formato exacto de la respuesta depende del entorno de ejecución. La respuesta de ejemplo está en formato JSON.

{
    "resultsReturned": "5",
    "executionDuration": "0.100718s",
    "readOperations": "5",
    "debugStats": {
               "index_entries_scanned": "95000",
               "documents_scanned": "5"
               "billing_details": {
                     "documents_billable": "5",
                     "index_entries_billable": "0",
                     "small_ops": "0",
                     "min_query_cost": "0",
               }
    }

}

Para obtener más información, consulta la referencia del informe de explicación de consultas.

Interpreta los resultados y haz ajustes

Veamos una situación de ejemplo en la que consultamos películas por género y país de producción.

A modo de ejemplo, supongamos el equivalente de esta consulta en SQL.

SELECT *
FROM /movies
WHERE category = 'Romantic' AND country = 'USA';

Si usamos la opción de analizar, las métricas que se muestran muestran que la consulta se ejecuta en dos índices de campo único, (category ASC, __name__ ASC) y (country ASC, __name__ ASC). Analiza 16,500 entradas de índice, pero solo muestra 1,200 documentos.

// Output query planning info
{
    "indexes_used": [
        {"query_scope": "Collection", "properties": "(category ASC, __name__ ASC)"},
        {"query_scope": "Collection", "properties": "(country ASC, __name__ ASC)"},
    ]
}

// Output query status
{
    "resultsReturned": "1200",
    "executionDuration": "0.118882s",
    "readOperations": "1200",
    "debugStats": {
               "index_entries_scanned": "16500",
               "documents_scanned": "1200"
               "billing_details": {
                     "documents_billable": "1200",
                     "index_entries_billable": "0",
                     "small_ops": "0",
                     "min_query_cost": "0",
               }
    }
}

Para optimizar el rendimiento de la ejecución de la consulta, puedes crear un índice compuesto completamente cubierto (category ASC, country ASC, __name__ ASC).

Si vuelves a ejecutar la consulta con la opción de análisis, podemos ver que el índice recién creado está seleccionado para esta consulta y que la consulta se ejecuta mucho más rápido y de manera más eficiente.

// Output query planning info
{
    "indexes_used": [
        {"query_scope": "Collection", "properties": "(category ASC, country ASC,  __name__ ASC)"}
    ]
}

// Output query stats
{
    "resultsReturned": "1200",
    "executionDuration": "0.026139s",
    "readOperations": "1200",
    "debugStats": {
               "index_entries_scanned": "1200",
               "documents_scanned": "1200"
               "billing_details": {
                     "documents_billable": "1200",
                     "index_entries_billable": "0",
                     "small_ops": "0",
                     "min_query_cost": "0",
               }
    }
}