Optimiser les requêtes avec des filtres de plage et d'inégalité sur plusieurs champs

Cette page fournit des exemples de stratégies d'indexation que vous pouvez utiliser pour les requêtes avec des filtres de plage et d'inégalité sur plusieurs champs pour créer expérience de requête.

Avant d'optimiser vos requêtes, consultez les concepts associés.

Optimiser les requêtes avec Query Explain

Pour déterminer si votre requête et vos index sont optimaux, utilisez la fonction Les requêtes Explain pour obtenir le résumé du plan de requête et les statistiques d'exécution de la requête:

Java

Query q = db.collection("employees").whereGreaterThan("salary",
100000).whereGreaterThan("experience", 0);

ExplainResults<QuerySnapshot> explainResults = q.explain(ExplainOptions.builder().analyze(true).build()).get();
ExplainMetrics metrics = explainResults.getMetrics();

PlanSummary planSummary = metrics.getPlanSummary();
ExecutionStats executionStats = metrics.getExecutionStats();

System.out.println(planSummary.getIndexesUsed());
System.out.println(stats.getResultsReturned());
System.out.println(stats.getExecutionDuration());
System.out.println(stats.getReadOperations());
System.out.println(stats.getDebugStats());

Node.js

let q = db.collection("employees")
      .where("salary", ">", 100000)
      .where("experience", ">",0);

let options = { analyze : 'true' };
let explainResults = await q.explain(options);

let planSummary = explainResults.metrics.planSummary;
let stats = explainResults.metrics.executionStats;

console.log(planSummary);
console.log(stats);

L'exemple suivant montre comment utiliser un classement correct des index réduit le nombre d'entrées d'index analysées par Firestore.

Requêtes simples

Avec l'exemple précédent d'une collection d'employés, la requête simple exécutée avec l'index (experience ASC, salary ASC) est la suivante :

Java

db.collection("employees")
  .whereGreaterThan("salary", 100000)
  .whereGreaterThan("experience", 0)
  .orderBy("experience")
  .orderBy("salary");

La requête analyse 95 000 entrées d'index pour renvoyer cinq documents. Puisque la requête si le prédicat n'est pas satisfait, un grand nombre d'entrées d'index sont lues, filtrées.

// Output query planning info
{
    "indexesUsed": [
        {
            "properties": "(experience ASC, salary ASC, __name__ ASC)",
            "query_scope": "Collection"
        }
    ],

    // Output Query Execution Stats
    "resultsReturned": "5",
    "executionDuration": "2.5s",
    "readOperations": "100",
    "debugStats": {
        "index_entries_scanned": "95000",
        "documents_scanned": "5",
        "billing_details": {
            "documents_billable": "5",
            "index_entries_billable": "95000",
            "small_ops": "0",
            "min_query_cost": "0"
        }
    }
}

Vous pouvez déduire de l'expertise du domaine que la plupart des employés auront au moins une certaine expérience, mais que peu d'entre eux auront un salaire supérieur à 100 000 €. Compte tenu de cette information, vous pouvez constater que la contrainte salary est plus sélective que la contrainte experience. Influencer l'index utilisé par Firestore pour exécuter la requête, spécifier une clause orderBy qui ordonne le paramètre salary avant la contrainte experience.

Java

db.collection("employees")
  .whereGreaterThan("salary", 100000)
  .whereGreaterThan("experience", 0)
  .orderBy("salary")
  .orderBy("experience");

Lorsque vous utilisez explicitement la clause orderBy() pour ajouter les prédicats, Firestore utilise l'index (salary ASC, experience ASC) pour exécuter la requête. Étant donné que la sélectivité du premier filtre de plage est plus élevée dans cette requête par rapport à la requête précédente, celle-ci s'exécute plus rapidement et est plus rentable.

// Output query planning info
{
    "indexesUsed": [
        {
            "properties": "(salary ASC, experience ASC, __name__ ASC)",
            "query_scope": "Collection"
        }
    ],

    // Output Query Execution Stats
    "resultsReturned": "5",
    "executionDuration": "0.2s",
    "readOperations": "6",
    "debugStats": {
        "index_entries_scanned": "1000",
        "documents_scanned": "5",
        "billing_details": {
            "documents_billable": "5",
            "index_entries_billable": "1000",
            "small_ops": "0",
            "min_query_cost": "0"
        }
    }
}

Étape suivante