Ottimizza le query con filtri per intervallo e disuguaglianze su più campi

Questa pagina fornisce esempi di strategie di indicizzazione che puoi utilizzare per le query con filtri per intervallo e disuguaglianza su più campi per creare una un'esperienza di query.

Prima di ottimizzare le query, leggi i concetti correlati.

Ottimizza le query con Query Explain

Per determinare se la query e gli indici sono ottimali, puoi utilizzare Query Spiega per ottenere il riepilogo e le statistiche di esecuzione del piano di query della query:

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'esempio seguente mostra come l'utilizzo dell'ordinamento corretto dell'indice riduce il numero di voci di indice sottoposte a scansione da Firestore.

Query semplici

Con l'esempio precedente di un insieme di dipendenti, la semplice query eseguito con l'indice (experience ASC, salary ASC) è il seguente:

Java

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

La query analizza solo 95.000 voci di indice per restituire cinque documenti. Poiché la query predicato non è soddisfatto, molte voci di indice vengono lette ma vengono esclusi.

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

Dall'esperienza nel settore si può dedurre che la maggior parte dei dipendenti avrà ma pochi hanno uno stipendio superiore a 100.000. In base a questa informazione, puoi vedere che il vincolo salary è più selettivo del vincolo experience. Per influenzare l'indice utilizzato da Firestore per eseguire la query, specifica una clausola orderBy che ordini il vincolo salary prima del vincolo experience.

Java

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

Quando utilizzi esplicitamente la clausola orderBy() per aggiungere i predicati, Firestore utilizza l'indice (salary ASC, experience ASC) per eseguire la query. Poiché la selettività del filtro del primo intervallo è più alta in questa query rispetto alla query precedente, la query viene eseguita più velocemente ed è più economica.

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

Passaggi successivi