Aby rozwiązać problemy z powolnymi zapytaniami, użyj funkcji Query Explain, aby uzyskać plan wykonywania zapytania i profil wykonywania w czasie działania. W sekcji poniżej opisano czynności, które możesz wykonać, aby zoptymalizować wydajność zapytania w zależności od profilu wykonywania:
Ograniczanie liczby wyników
Użyj pola zwróconych rekordów w drzewie wykonania, aby sprawdzić, czy zapytanie zwraca wiele dokumentów. Rozważ ograniczenie liczby zwracanych dokumentów za pomocą etapu limit(...). Zmniejsza to rozmiar zserializowanych bajtów wyników zwracanych klientom przez sieć. W przypadkach, gdy węzeł Limit jest poprzedzony węzłem MajorSort, mechanizm zapytań może połączyć węzły Limit i MajorSort oraz zastąpić pełną materializację i sortowanie w pamięci sortowaniem TopN, co zmniejsza zapotrzebowanie zapytania na pamięć.
Ograniczanie rozmiaru dokumentu wynikowego
Rozważ ograniczenie rozmiaru zwracanego dokumentu, używając select(...), aby zwracać tylko wymagane pola, lub remove_fields(...), aby odrzucać zbyt duże pola. Pomaga to zmniejszyć koszty obliczeniowe i pamięciowe przetwarzania wyników pośrednich oraz rozmiar zserializowanych bajtów wyników zwracanych klientom przez sieć. W przypadkach, gdy wszystkie pola, do których odwołuje się zapytanie, są objęte zwykłym indeksem, umożliwia to również pełne objęcie zapytania skanowaniem indeksu, co eliminuje konieczność pobierania dokumentów z pamięci głównej.
Używanie indeksów
Aby skonfigurować i zoptymalizować indeksy, postępuj zgodnie z poniższymi instrukcjami.
Sprawdzanie, czy zapytanie używa indeksu
Możesz sprawdzić, czy zapytanie używa indeksu, sprawdzając węzły liści w drzewie wykonywania. Jeśli węzeł liścia drzewa wykonywania jest węzłem TableScan, oznacza to, że zapytanie nie używa indeksu i skanuje dokumenty z pamięci podstawowej. Jeśli używany jest indeks, węzeł liścia drzewa wykonania wyświetli identyfikator indeksu i pola indeksu.
Identyfikowanie lepszego indeksu
Indeks jest przydatny w przypadku zapytania, jeśli może zmniejszyć liczbę dokumentów, które mechanizm zapytań musi pobrać z pamięci podstawowej, lub jeśli kolejność pól może spełnić wymagania dotyczące sortowania zapytania.
Jeśli indeks jest używany w zapytaniu, ale mechanizm zapytań nadal pobiera i odrzuca wiele dokumentów, co jest identyfikowane przez węzeł skanowania, który zwraca wiele rekordów, a następnie węzeł filtra, który zwraca niewiele rekordów, oznacza to, że predykat zapytania spełniony przy użyciu indeksu nie jest selektywny. Aby utworzyć bardziej odpowiedni indeks, zapoznaj się z artykułem Tworzenie indeksów.
Jeśli indeks jest używany w zapytaniu, ale mechanizm zapytań nadal wykonuje zmianę kolejności zbioru wyników w pamięci, co jest identyfikowane przez węzeł MajorSort w drzewie wykonywania zapytania, oznacza to, że użytego indeksu nie można użyć do spełnienia wymagania sortowania zapytania. Aby utworzyć bardziej odpowiedni indeks, zapoznaj się z następną sekcją.
Tworzenie indeksów
Aby utworzyć indeksy, postępuj zgodnie z dokumentacją dotyczącą zarządzania indeksami. Aby mieć pewność, że zapytanie może używać indeksów, utwórz zwykłe indeksy (nie wielokluczowe) z polami w tej kolejności:
- Wszystkie pola, które będą używane w operatorach równości. Aby zmaksymalizować szansę na ponowne użycie w zapytaniach, uporządkuj pola w kolejności malejącej według występowania pól w operatorach równości w zapytaniach.
- Wszystkie pola, według których będzie przeprowadzane sortowanie (w tej samej kolejności).
- Pola, które będą używane w operatorach zakresu lub nierówności, w kolejności malejącej selektywności ograniczeń zapytania.
- Pola, które zostaną zwrócone w ramach zapytania w indeksie: uwzględnienie takich pól w indeksie pozwala mu objąć zapytanie i uniknąć konieczności pobierania dokumentu z pamięci głównej.
Wymuszanie skanowania indeksu lub tabeli
Gdy wysyłasz zapytanie do Cloud Firestore, automatycznie używa on indeksów, które mogą zwiększyć wydajność zapytania. Dzięki temu nie musisz określać indeksu dla zapytań. W przypadku zapytań, które mają kluczowe znaczenie dla Twojego zbioru zadań, zalecamy jednak użycie opcji forceIndex, aby uzyskać bardziej spójną wydajność.
W niektórych przypadkach Cloud Firestore może wybrać indeks, który zwiększa czas oczekiwania na zapytanie. Jeśli po wykonaniu czynności opisanych w sekcji dotyczącej rozwiązywania problemów ze spadkiem wydajności uznasz, że warto wypróbować inny indeks dla zapytania, możesz określić indeks za pomocą opcji forceIndex.
Możesz użyć opcji forceIndex na dowolnym etapie wejściowym w operacjach potoku, aby zastąpić domyślny plan zapytania Cloud Firestore i określić indeks do użycia lub wymusić skanowanie tabeli.
Wymuszanie określonego indeksu
Aby wymusić użycie określonego indeksu przez zapytanie, podaj identyfikator indeksu jako ciąg znaków w opcji forceIndex. Identyfikator indeksu znajdziesz w konsoli lub w komunikatach o błędach.
Poniższy przykład wymusza na planiście użycie indeksu o identyfikatorze CICAgOi36pgK:
Node.js
// Force Planner to use Index ID CICAgOi36pgK await db.pipeline() .collectionGroup({ collectionId: "customers", forceIndex: "CICAgOi36pgK" }) .limit(100) .execute();
Java
// Force Planner to use Index ID CICAgOi36pgK Pipeline.Snapshot results1 = firestore.pipeline() .collectionGroup("customers", new CollectionGroupOptions() .withHints(new CollectionHints().withForceIndex("CICAgOi36pgK"))) .limit(100) .execute().get();
Go
// Force Planner to use Index ID CICAgOi36pgK snapshot1 := client.Pipeline(). CollectionGroup("customers", firestore.WithForceIndex("CICAgOi36pgK")). Limit(100). Execute(ctx)
Oto kilka przypadków użycia, w których warto wymusić użycie konkretnego indeksu:
- testowanie wydajności różnych indeksów;
- zapewnienie, że w zapytaniu zostanie użyty konkretny, znany jako optymalny indeks;
- zastępowanie optymalizatora, gdy jego domyślny wybór jest nieoptymalny w przypadku konkretnego zapytania;
Jeśli nie znajdzie określonego indeksu, zapytanie się nie powiedzie.
Wymuszanie skanowania tabeli
Skanowanie tabeli odczytuje dokumenty w kolekcji lub grupie kolekcji bez użycia indeksów pomocniczych. Aby wymusić skanowanie tabeli, ustaw forceIndex na primary.
Poniższy przykład wymusza skanowanie tabeli:
// Force Planner to only do a Full-Table Scan
db.pipeline()
.collectionGroup({ collectionId: "customers", forceIndex: "primary" })
.limit(100)
Skanowanie tabeli może być przydatne w tych przypadkach:
- bardzo małych kolekcji, w przypadku których narzut indeksu nie jest uzasadniony;
- W przypadku zapytań, które uzyskują dostęp do większości dokumentów w kolekcji.
- Do debugowania i porównywania wydajności.
Korzystanie z forceIndex z wyjaśnieniem zapytania
Możesz użyć wyjaśnienia zapytania w trybie explain lub analyze, aby obserwować efekty działania forceIndex:
- Sprawdź, czy usługa Cloud Firestore użyła określonego indeksu w
forceIndex, sprawdzając węzły liści drzewa wykonania pod kątem identyfikatora indeksu. - Sprawdź, czy podczas korzystania z
forceIndex: "primary"w planie pojawia się węzełTableScan. - W trybie
analyzeporównaj wskaźniki skuteczności, takie jak czas oczekiwania, zeskanowane dokumenty i zeskanowane wpisy indeksu, z użyciemforceIndexi bez niego, aby dostosować wydajność zapytań.
forceIndex – sprawdzone metody
Chociaż forceIndex zapewnia większą kontrolę nad wykonywaniem zapytań, optymalizator zapytań Cloud Firestore jest ogólnie skuteczny w większości przypadków użycia.
Podczas korzystania z atrybutu forceIndex weź pod uwagę te sprawdzone metody:
- Używaj
forceIndexz rozwagą. Jeśli zauważysz nieoptymalną wydajność domyślnego planu zapytania, przed wymuszeniem indeksu użyj funkcji Query Explain, aby zdiagnozować problem. - Gdy używasz
forceIndex, przetestuj zapytania z realistycznymi ilościami danych, aby poznać ich charakterystykę pod względem wydajności i kosztów. - Unikaj używania
forceIndex: "primary"w dużych kolekcjach w środowiskach produkcyjnych.
Więcej informacji o danych wyjściowych zapytania wykonanego za pomocą funkcji wyjaśniania zapytań znajdziesz w artykule Informacje o wykonywaniu zapytań.