Questa pagina fornisce esempi della strategia di indicizzazione da utilizzare per le query con filtri di intervallo e disuguaglianza su più campi al fine di creare un'esperienza di query efficiente.
Leggi i concetti relativi ai filtri di intervallo e disuguaglianza su più proprietà prima di ottimizzare le query.
Ottimizza le query con la spiegazione delle query
Per determinare se la query e gli indici utilizzati sono ottimali, puoi creare una query utilizzando Query Explain ed esaminare il riepilogo dell'esecuzione.
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));
L'esempio seguente mostra come l'uso di un ordinamento corretto dell'indice salva il numero di entità che Firestore in modalità Datastore analizza.
Query semplici
Con l'esempio precedente di una raccolta di dipendenti, la semplice query
eseguita con l'indice (salary, experience)
è la seguente:
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();
La query analizza solo 95.000 voci di indice per restituire cinque entità. Un numero elevato di voci di indice è stato letto ma filtrato perché non soddisfacevano il predicato della query.
// 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" } } }
Come nell'esempio precedente, possiamo dedurre che il vincolo salary
è più
selettivo del vincolo 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();
Quando usi esplicitamente la clausola orderBy()
per aggiungere i predicati nell'ordine precedente, Firestore in modalità Datastore utilizza l'indice (salary, experience)
per eseguire la query. Di conseguenza, poiché la selezione del filtro del primo intervallo è migliore rispetto alla query precedente, la query viene eseguita più velocemente ed è più economica.
// 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" } } }
Passaggi successivi
- Scopri di più su Query Explain.