Auf dieser Seite finden Sie Beispiele für Indexierungsstrategien, die Sie für Abfragen verwenden können mit Bereichs- und Ungleichheitsfiltern auf mehrere Felder, um eine effiziente die Nutzerfreundlichkeit von Abfragen.
Vor der Optimierung finden Sie unter Bereichs- und Ungleichheitsfilter für mehrere Attribute .
Abfragen mit Query Explain optimieren
Um festzustellen, ob die verwendete Abfrage und die Indexe optimal sind, können Sie eine Abfrage mit Abfrageerläuterung 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));
Das folgende Beispiel zeigt, wie bei Verwendung der richtigen Indexreihenfolge die Anzahl der Entitäten, die Firestore im Datastore-Modus scannt.
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" } } }
Aus dem obigen Beispiel können wir ableiten, dass die Einschränkung salary
stärker
selektiver als die Beschränkung experience
.
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" } } }