Comprendre les performances des requêtes à l'aide de Query Explain

L'explication des requêtes vous permet d'envoyer des requêtes Firestore au backend et de recevoir en retour des statistiques détaillées sur les performances de l'exécution des requêtes backend. Il fonctionne comme l'opération EXPLAIN [ANALYZE] dans de nombreux systèmes de bases de données relationnelles.

Les requêtes d'explication de requête peuvent être envoyées à l'aide des bibliothèques clientes du serveur Firestore.

Les résultats de la fonctionnalité Query Explain vous permettent de comprendre le fonctionnement de vos requêtes. ce qui vous montre les inefficacités et l'emplacement les goulots d'étranglement.

Explication de la requête:

  • Fournit des insights sur la phase de planification des requêtes afin que vous puissiez ajuster vos index de requêtes et améliorer l'efficacité.
  • L'option d'analyse vous aide à comprendre les coûts et les performances chaque requête et vous permet d'itérer rapidement les différentes des modèles afin d'optimiser leur utilisation.

Comprendre les options Query Explain : "default" et "analyze"

Les opérations Query Explain peuvent être effectuées à l'aide de l'option default ou analyze.

Avec l'option par défaut, l'explication de la requête planifie la requête, mais ignore l'étape d'exécution. Vous obtiendrez ainsi des informations sur les étapes du planificateur. Vous pouvez utilisez-le pour vérifier qu'une requête dispose des index nécessaires et identifier sont utilisés. Cela vous aidera à vérifier, par exemple, qu'un utilise un index composite plutôt que d'avoir à croiser de nombreux éléments index.

Avec l'option d'analyse, Query Explain propose les deux plans et exécute la requête. Cette commande renvoie toutes les informations du planificateur mentionnées précédemment, ainsi que les statistiques de l'environnement d'exécution de l'exécution de la requête. Cela inclut la facturation des informations sur la requête, ainsi que des insights système l'exécution. Vous pouvez utiliser cet outil pour tester différentes requêtes afin d'optimiser leurs coûts et leur latence.

Quel est le coût de l'explication des requêtes ?

Lorsque vous utilisez l'option par défaut de l'explication de requête, aucune opération d'indexation ni de lecture n'est effectuée. Une opération de lecture est facturée, quelle que soit la complexité de la requête.

Lorsque vous utilisez l'explication de requête avec l'option d'analyse, des opérations d'indexation et de lecture sont effectuées. La requête vous est donc facturée comme d'habitude. L'activité d'analyse n'entraîne aucuns frais supplémentaires, mais uniquement les frais habituels pour la requête exécutée.

Utiliser l'explication de la requête avec l'option par défaut

Vous pouvez utiliser les bibliothèques clientes pour envoyer une requête d'option par défaut.

Notez que les requêtes sont authentifiées avec IAM, en utilisant les mêmes autorisations que pour les opérations de requêtes standards. Les autres techniques d'authentification, comme Firebase Authentication, sont ignorées. Pour en savoir plus, consultez le guide sur IAM pour les bibliothèques clientes de serveur

Java (administrateur)

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();

    
Nœud (administrateur)

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;

    

Le format exact de la réponse dépend de l'environnement d'exécution. Les résultats renvoyés peuvent être convertis au format JSON. Exemple :

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

Pour en savoir plus, consultez la documentation de référence sur le rapport d'explication de requête.

Utiliser l'explication de requête avec l'option d'analyse

Vous pouvez utiliser les bibliothèques clientes pour envoyer une requête d'option d'analyse.

Notez que les requêtes sont authentifiées avec IAM à l'aide de la même pour les opérations de requête standards. D'autres techniques d'authentification, telles que Firebase Authentication sont ignorés. Pour en savoir plus, consultez le guide sur l'IAM pour les bibliothèques clientes de serveur.

Java (administrateur)

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();

    
Nœud (administrateur)

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;

    

L'exemple suivant montre l'objet stats renvoyé en plus de planInfo. Le format exact de la réponse dépend de l'environnement d'exécution. L'exemple de réponse est au format 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",
               }
    }

}

Pour en savoir plus, consultez la documentation de référence sur le rapport d'explication de requête.

Interpréter les résultats et procéder à des ajustements

Examinons un exemple de scénario dans lequel nous interrogeons les films par genre et le pays de production.

À titre d'illustration, supposons l'équivalent de cette requête SQL.

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

Si nous utilisons l'option d'analyse, les métriques renvoyées indiquent la requête s'exécute sur deux index à champ unique : (category ASC, __name__ ASC) et (country ASC, __name__ ASC) Il analyse 16 500 entrées d'index, mais renvoie que 1 200 documents.

// 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",
               }
    }
}

Pour optimiser les performances de l'exécution de la requête, vous pouvez créer un (category ASC, country ASC, __name__ ASC) d'index composite entièrement couvert.

En exécutant à nouveau la requête avec l'option d'analyse, nous pouvons voir que l'index nouvellement créé est sélectionné pour cette requête, et qu'elle s'exécute beaucoup plus rapidement et plus efficacement.

// 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",
               }
    }
}