Optimiser les requêtes avec des filtres de plage et d'inégalité sur plusieurs propriétés

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