Optymalizuj zapytania za pomocą filtrów zakresów i nierówności w wielu polach

Na tej stronie znajdziesz przykłady strategii indeksowania, których możesz używać w zapytaniach z filtrami zakresu i nierówności w różnych polach, aby zwiększyć efektywność zapytań.

Przed zoptymalizowaniem zapytań zapoznaj się z powiązanymi pojęciami.

Optymalizowanie zapytań za pomocą Query Explain

Aby określić, czy Twoje zapytanie i indeksy są optymalne, możesz użyć polecenia Query Explain, aby uzyskać podsumowanie planu zapytania i statystyki wykonania zapytania:

Java

Query q = db.collection("employees").whereGreaterThan("salary",
100000).whereGreaterThan("experience", 0);

ExplainResults<QuerySnapshot> explainResults = q.explain(ExplainOptions.builder().analyze(true).build()).get();
ExplainMetrics metrics = explainResults.getMetrics();

PlanSummary planSummary = metrics.getPlanSummary();
ExecutionStats executionStats = metrics.getExecutionStats();

System.out.println(planSummary.getIndexesUsed());
System.out.println(stats.getResultsReturned());
System.out.println(stats.getExecutionDuration());
System.out.println(stats.getReadOperations());
System.out.println(stats.getDebugStats());

Node.js

let q = db.collection("employees")
      .where("salary", ">", 100000)
      .where("experience", ">",0);

let options = { analyze : 'true' };
let explainResults = await q.explain(options);

let planSummary = explainResults.metrics.planSummary;
let stats = explainResults.metrics.executionStats;

console.log(planSummary);
console.log(stats);

Poniższy przykład pokazuje, jak zastosowanie prawidłowej kolejności indeksu zmniejsza liczbę wpisów indeksu skanowanych przez Cloud Firestore.

proste zapytania,

W wcześniejszym przykładzie zbioru pracowników proste zapytanie uruchamiane z indeksem (experience ASC, salary ASC) wygląda tak:

Java

db.collection("employees")
  .whereGreaterThan("salary", 100000)
  .whereGreaterThan("experience", 0)
  .orderBy("experience")
  .orderBy("salary");

Zapytanie skanuje tylko 95 000 wpisów indeksu, aby zwrócić 5 dokumentów. Ponieważ predykat zapytania nie jest spełniony, odczytywana jest duża liczba wpisów w indeksie, ale są one odfiltrowywane.

// Output query planning info
{
    "indexesUsed": [
        {
            "properties": "(experience ASC, salary ASC, __name__ ASC)",
            "query_scope": "Collection"
        }
    ],

    // 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"
        }
    }
}

Na podstawie specjalistycznej wiedzy w danej dziedzinie możesz wywnioskować, że większość pracowników ma co najmniej pewne doświadczenie, ale niewiele osób zaoferuje wynagrodzenie powyżej 1 000 000 000. Biorąc pod uwagę te dane, możesz zauważyć, że ograniczenie salary jest bardziej selektywne niż ograniczenie experience. Aby wpływać na indeks, którego Cloud Firestore używa do wykonywania zapytania, określ klauzulę orderBy, która porządkuje ograniczenie salary przed ograniczeniem experience.

Java

db.collection("employees")
  .whereGreaterThan("salary", 100000)
  .whereGreaterThan("experience", 0)
  .orderBy("salary")
  .orderBy("experience");

Gdy dodajesz predykaty, używając wyraźnie klauzuli orderBy(), funkcja Cloud Firestore używa indeksu (salary ASC, experience ASC) do wykonywania zapytań. Selektywność pierwszego filtra zakresu jest w tym zapytaniu większa w porównaniu z poprzednim zapytaniem, dlatego zapytanie działa szybciej i jest tańsze.

// Output query planning info
{
    "indexesUsed": [
        {
            "properties": "(salary ASC, experience ASC, __name__ ASC)",
            "query_scope": "Collection"
        }
    ],

    // 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"
        }
    }
}

Co dalej?