Na tej stronie znajdziesz przykłady strategii indeksowania, których możesz używać w przypadku zapytań z filtrami zakresu i nierówności w wielu polach, aby zapewnić wydajne wykonywanie zapytań.
Zanim zoptymalizujesz zapytania, zapoznaj się z powiązanymi pojęciami.
Optymalizacja zapytań za pomocą narzędzia Query Explain
Aby sprawdzić, czy zapytanie i indeksy są optymalne, możesz użyć narzędzia Query Explain, aby uzyskać podsumowanie planu zapytania i statystyki jego wykonania:
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 użycie prawidłowego porządkowania indeksów zmniejsza liczbę wpisów indeksu skanowanych przez Cloud Firestore.
Proste zapytania
W przypadku wcześniejszego przykładu kolekcji pracowników proste zapytanie
które jest wykonywane 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 tys. wpisów indeksu, aby zwrócić 5 dokumentów. Ponieważ predykat zapytania nie jest spełniony, odczytywana jest duża liczba wpisów indeksu, które są jednak 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 o domenie można wywnioskować, że większość pracowników będzie mieć co najmniej pewne doświadczenie, ale niewielu będzie zarabiać więcej niż 100 tys. Biorąc to pod uwagę, widać, że ograniczenie salary jest bardziej selektywne niż ograniczenie experience. Aby wpłynąć na indeks, którego Cloud Firestore używa do
wykonania 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 do dodania predykatów używasz jawnie klauzuli orderBy(),
Cloud Firestore używa do wykonania zapytania indeksu (salary ASC, experience ASC).
Ponieważ selektywność pierwszego filtra zakresu jest w tym zapytaniu wyższa niż w poprzednim, zapytanie działa szybciej i jest bardziej opłacalne.
// 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?
- Więcej informacji o narzędziu Query Explain
- Więcej informacji o sprawdzonych metodach indeksowania.