Cette page fournit des exemples de stratégies d'indexation que vous pouvez utiliser pour les requêtes avec des filtres de plage et d'inégalité sur plusieurs champs pour créer expérience de requête.
Avant d'optimiser vos requêtes, consultez les concepts de filtres de plage et d'inégalité sur plusieurs propriétés.
Optimiser les requêtes avec l'explication des requêtes
Pour déterminer si la requête et les index utilisés sont optimaux, vous pouvez créer une requête à l'aide de Query Explain, puis examinez le résumé de l'exécution.
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'exemple suivant montre comment l'utilisation d'un ordre d'index correct permet de réduire le nombre d'entités que Firestore en mode Datastore analyse.
Requêtes simples
Dans l'exemple précédent d'un ensemble d'employés, la requête simple
qui s'exécute avec l'index (salary, experience)
se présente comme suit:
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 requête analyse 95 000 entrées d'index pour renvoyer seulement cinq entités. Un grand nombre des entrées d'index ont été lues, mais filtrées, car elles ne répondaient pas aux exigences de la prédicat de requête.
// 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" } } }
Comme dans l'exemple précédent, nous pouvons en déduire que la contrainte salary
est plus
que la contrainte 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();
Lorsque vous utilisez explicitement la clause orderBy()
pour ajouter les prédicats dans le
ordre antérieur, Firestore en mode Datastore utilise l'index (salary, experience)
pour exécuter la requête. Étant donné que la sélection du premier filtre de plage est meilleure que la requête précédente, la requête s'exécute plus rapidement et est rentable.
// 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" } } }
Étape suivante
- En savoir plus sur l'explication des requêtes