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

Auf dieser Seite finden Sie Beispiele für Indexierungsstrategien, die Sie für Abfragen mit Bereichs- und Ungleichheitsfiltern auf mehreren Feldern verwenden können, um Abfragen effizienter zu gestalten.

Bevor Sie Ihre Abfragen optimieren, sollten Sie sich mit den Konzepten zu Bereichs- und Ungleichheitsfiltern für mehrere Properties vertraut machen .

Abfragen mit „Abfrage erläutern“ optimieren

Wenn Sie feststellen möchten, ob die verwendete Abfrage und die Indexe optimal sind, können Sie mit Abfrageerläuterung eine Abfrage erstellen und die Ausführungsübersicht prüfen.

Java

...
// Build the query
Query<Entity> query =
    Query.newEntityQueryBuilder()
        .setKind("employees")
        .setFilter(
            CompositeFilter.and(
                PropertyFilter.gt("salary", 100000), PropertyFilter.gt("experience", 0)))
        .setOrderBy(OrderBy("experience"), OrderBy("salary"))
        .build();

// Set the explain options to get back *only* the plan summary
ExplainResults<Entity> explainResults = datastore.run(query, ExplainOptions.newBuilder().build());

// Get the explain metrics
Optional<ExplainMetrics> explainMetrics = results.getExplainMetrics();
if (!explainMetrics.isPresent()) {
  throw new Exception("No explain metrics returned");
}

// Get the plan summary
PlanSummary planSummary = explainMetrics.get().getPlanSummary();
List<Map<String, Object>> indexesUsed = planSummary.getIndexesUsed();
System.out.println("----- Indexes Used -----");
indexesUsed.forEach(map -> map.forEach((s, o) -> System.out.println(s + ": " + o)));

// Get the execution stats
if (!explainMetrics.getExecutionStats().isPresent()) {
  throw new Exception("No execution stats returned");
}

ExecutionStats queryStats = explainMetrics.getExecutionStats().get();
Map<String, Object> debugStats = queryStats.getDebugStats();
System.out.println("----- Debug Stats -----");
debugStats.forEach((s, o) -> System.out.println(s + ": " + o));

Im folgenden Beispiel wird gezeigt, wie durch die richtige Indexreihenfolge die Anzahl der Entitäten reduziert wird, die in Firestore im Datastore-Modus gescannt werden.

Einfache Abfragen

Für das vorherige Beispiel mit einer Sammlung von Mitarbeitern sieht die einfache Abfrage, die mit dem Index (salary, experience) ausgeführt wird, so aus:

GQL

SELECT *
FROM /employees
WHERE salary > 100000 AND experience > 0
ORDER BY experience, salary;

Java

Query<Entity> query =
   Query.newEntityQueryBuilder()
    .setKind("employees")
    .setFilter(
        CompositeFilter.and(
            PropertyFilter.gt("salary", 100000), PropertyFilter.gt("experience", 0)))
    .setOrderBy(OrderBy("experience"), OrderBy("salary"))
    .build();

Die Abfrage scannt 95.000 Indexeinträge, um nur 5 Entitäten zurückzugeben. Eine große Anzahl von Indexeinträgen wurde gelesen, aber herausgefiltert, weil sie nicht dem Abfrageprädikat entsprachen.

// Output query planning info
{
        "indexesUsed": [
            {
                "query_scope": "Collection Group",
                "properties": "(experience ASC, salary ASC, __name__ ASC)"
            }
        ]
    },
    // 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"
            }
        }
    }

Wie im vorherigen Beispiel können wir daraus schließen, dass die salary-Einschränkung selektiver ist als die experience-Einschränkung.

GQL

SELECT *
FROM /employees
WHERE salary > 100000 AND experience > 0
ORDER BY salary, experience;

Java

Query<Entity> query =
   Query.newEntityQueryBuilder()
    .setKind("employees")
    .setFilter(
        CompositeFilter.and(
            PropertyFilter.gt("salary", 100000), PropertyFilter.gt("experience", 0)))
    .setOrderBy(OrderBy("salary"), OrderBy("experience"))
    .build();

Wenn Sie die orderBy()-Klausel explizit verwenden, um die Prädikate in der vorherigen Reihenfolge hinzuzufügen, verwendet Firestore im Datastore-Modus den (salary, experience)-Index, um die Abfrage auszuführen. Da die Auswahl des ersten Bereichsfilters besser ist als bei der vorherigen Abfrage, wird die Abfrage schneller ausgeführt und ist kosteneffizienter.

    // Output query planning info
{
    "indexesUsed": [
        {
            "query_scope": "Collection Group",
            "properties": "(salary ASC, experience ASC, __name__ ASC)"
        }
    ],
    // 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