Abfragen mit Bereichs- und Ungleichheitsfiltern für mehrere Felder optimieren

Auf dieser Seite finden Sie Beispiele für Indexierungsstrategien, die Sie für Abfragen mit Bereichs- und Ungleichheitsfiltern für mehrere Felder verwenden können, um effiziente Abfragen zu erstellen.

Bevor Sie Ihre Abfragen optimieren, lesen Sie die Informationen zu den entsprechenden Konzepten.

Abfragen mit Query Explain optimieren

Mit Query Explain können Sie prüfen, ob Ihre Abfrage und Indexe optimal sind. Dazu rufen Sie die Zusammenfassung des Abfrageplans und die Ausführungsstatistiken der Abfrage ab:

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

Das folgende Beispiel zeigt, wie durch die Verwendung der richtigen Indexreihenfolge die Anzahl der Indexeinträge reduziert wird, die von Cloud Firestore gescannt werden.

Einfache Abfragen

Im vorherigen Beispiel mit einer Sammlung von Mitarbeitern sieht die einfache Abfrage, die mit dem (experience ASC, salary ASC) Index ausgeführt wird, so aus:

Java

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

Die Abfrage scannt nur 95.000 Indexeinträge, um fünf Dokumente zurückzugeben. Da das Abfrageprädikat nicht erfüllt ist, wird eine große Anzahl von Indexeinträgen gelesen, aber herausgefiltert.

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

Aus der Fachkenntnis der Domain lässt sich ableiten, dass die meisten Mitarbeiter über einige Erfahrung verfügen, aber nur wenige ein Gehalt von mehr als 100.000 haben. Aus dieser Erkenntnis lässt sich schließen, dass die Einschränkung salary selektiver ist als die Einschränkung experience. Wenn Sie den Index beeinflussen möchten, den Cloud Firestore zum Ausführen der Abfrage verwendet, geben Sie eine orderBy Klausel an, die die salary Einschränkung vor der experience Einschränkung anordnet.

Java

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

Wenn Sie die orderBy()-Klausel explizit verwenden, um die Prädikate hinzuzufügen, verwendet Cloud Firestore den Index (salary ASC, experience ASC), um die Abfrage auszuführen. Da die Selektivität des ersten Bereichsfilters in dieser Abfrage höher ist als in der vorherigen Abfrage, wird die Abfrage schneller ausgeführt und ist kostengünstiger.

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

Nächste Schritte