Questa pagina fornisce esempi di strategie di indicizzazione che puoi utilizzare per le query con filtri di intervallo e disuguaglianza su più campi per creare un'esperienza di query efficiente.
Prima di ottimizzare consulta i concetti relativi ai filtri di intervalli e disuguaglianze su più proprietà .
Ottimizza le query con Query Explain
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'utilizzo dell'ordinamento corretto degli indici consente di risparmiare sul numero di entità sottoposte a scansione da parte di Firestore in modalità Datastore.
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 5 entità. Un numero elevato delle voci di indice sono state lette ma escluse perché non soddisfacevano 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 rispetto al 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 utilizzi esplicitamente la clausola orderBy()
per aggiungere i predicati nell'ordine precedente, Firestore in modalità Datastore utilizza l'indice (salary, experience)
per eseguire la query. Poiché la selezione del primo filtro dell'intervallo è migliore rispetto alla query precedente, la query viene eseguita più velocemente ed è conveniente.
// 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.