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

Auf dieser Seite finden Sie Beispiele für Indexierungsstrategien, die bei Abfragen mit Bereichs- und Ungleichheitsfiltern für mehrere Felder verwendet werden sollten, um eine effiziente Abfrageumgebung zu schaffen.

Informieren Sie sich über die verwandten Konzepte, bevor Sie Ihre Abfragen optimieren.

Abfragen mit Query Explain optimieren

Um festzustellen, ob die verwendete Abfrage und die verwendeten Indexe optimal sind, können Sie mit Query Explain die Zusammenfassung des Abfrageplans und die Ausführungsstatistiken der Abfrage abrufen:

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 Firestore scannt.

Einfache Abfragen

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

Java

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

Die Abfrage scannt 95.000 Indexeinträge und gibt nur 5 Dokumente zurück. 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 dem Domänenwissen können wir ableiten, dass die meisten Mitarbeitenden zumindest ein wenig Erfahrung haben, aber nur wenige ein Gehalt von mehr als 100.000 $ haben werden. Aus diesen Erkenntnissen können wir schließen, dass die Einschränkung salary selektiver ist als die Einschränkung experience. Um den Index zu beeinflussen, den Firestore zum Ausführen der Abfrage verwendet, geben Sie eine orderBy-Klausel an, die die Einschränkung salary vor der Einschränkung experience sortiert.

Java

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

Wenn Sie die Prädikate explizit mit der Klausel orderBy() hinzufügen, verwendet Firestore den Index (salary ASC, experience ASC) zum Ausführen der Abfrage. Da die Selektivität des ersten Bereichsfilters bei dieser Abfrage im Vergleich zur vorherigen Abfrage höher ist, wird die Abfrage schneller und kostengünstiger ausgeführt.

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

Weitere Informationen