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 Anfragen optimieren, sollten Sie sich mit den zugehörigen Konzepten vertraut machen.

Abfragen mit Query Explain optimieren

Um festzustellen, ob Ihre Abfrage und Ihre Indexe optimal sind, können Sie Query Explain verwenden, um die Zusammenfassung des Abfrageplans und die Ausführungsstatistiken der Abfrage abzurufen:

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

Im folgenden Beispiel wird gezeigt, 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 für eine 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");

Bei der Abfrage werden nur 95.000 Indexeinträge gescannt, um fünf Dokumente zurückzugeben. Da das Abfrageprädikat nicht erfüllt ist, wird eine große Anzahl von Indexeinträgen gelesen, die jedoch herausgefiltert werden.

// 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 Domäne lässt sich ableiten, dass die meisten Mitarbeiter zumindest etwas Erfahrung haben, aber nur wenige ein Gehalt von mehr als 100.000 € haben. Aus dieser Erkenntnis geht hervor, 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, in der die salary-Einschränkung vor der experience-Einschränkung angeordnet wird.

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 (salary ASC, experience ASC)-Index, um die Abfrage auszuführen. Da die Selektivität des ersten Bereichsfilters in dieser Abfrage höher ist als in der vorherigen, 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