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żyć w przypadku zapytań z filtrami zakresów i nierówności w wielu polach, aby uzyskać i zapytania.

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

Optymalizowanie zapytań za pomocą Query Explain

Aby określić, czy zapytanie i indeksy są optymalne, możesz użyć funkcji Zapytanie Wyjaśnij, aby uzyskać podsumowanie planu zapytania i statystyki wykonywania 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ę pozycji indeksu, które skanuje Cloud Firestore.

Proste zapytania

W przypadku wcześniejszego przykładu zbioru pracowników proste zapytanie, które jest wykonywane przy użyciu indeksu (experience ASC, salary ASC), ma postać:

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 wiedzy merytorycznej można wywnioskować, że większość pracowników zatrudnia ale niewiele osób zaoferuje pensję powyżej 10 000 000. Mając to na uwadze możesz zobaczyć, że ograniczenie salary jest bardziej selektywne niż Ograniczenie experience. Aby wpłynąć na indeks używany przez Cloud Firestore do wykonaj zapytanie, określ klauzulę orderBy, która porządkuje salary przed ograniczeniem experience.

Java

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

Jeśli dodasz predykaty za pomocą klauzuli orderBy(), Do uruchomienia zapytania Cloud Firestore używa indeksu (salary ASC, experience ASC). W tym zapytaniu pierwsze ograniczenie zakresu jest bardziej selektywne niż w poprzednim zapytaniu, więc jest ono wykonywane szybciej i bardziej ekonomicznie.

// 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?