Aby rozwiązać problemy z powolnymi zapytaniami, użyj funkcji Query Explain, aby uzyskać plan wykonania zapytania i profil wykonania w czasie działania. W sekcji poniżej znajdziesz opis czynności, które możesz wykonać, aby zoptymalizować wydajność zapytania w zależności od profilu wykonania:
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 serializowanych bajtów wyników zwracanych klientom przez sieć. W przypadku, gdy węzeł Limit jest poprzedzony węzłem MajorSort, silnik 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 wymagania dotyczące pamięci w przypadku zapytania.
Ograniczanie rozmiaru dokumentu wynikowego
Rozważ ograniczenie rozmiaru zwracanego dokumentu za pomocą parametru select(...), aby zwracać tylko wymagane pola, lub parametru remove_fields(...), aby odrzucać zbyt duże pola. Pomaga to zmniejszyć koszty obliczeniowe i koszty pamięci związane z przetwarzaniem wyników pośrednich oraz rozmiar serializowanych wyników w bajtach, gdy są one zwracane do klientów przez sieć. W przypadku, gdy wszystkie pola, do których odwołuje się zapytanie, są objęte zwykłym indeksem, umożliwia to również pełne pokrycie zapytania przez skanowanie indeksu, co pozwala uniknąć pobierania dokumentów z pamięci podstawowej.
Korzystanie z indeksów
Aby skonfigurować i zoptymalizować indeksy, postępuj zgodnie z tymi instrukcjami.
Sprawdzanie, czy zapytanie używa indeksu
Aby sprawdzić, czy zapytanie korzysta z indeksu, możesz przejrzeć węzły liści w drzewie wykonania. Jeśli węzeł liścia drzewa wykonania 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 będzie wyświetlać identyfikator indeksu i pola indeksu.
Znajdowanie lepszego indeksu
Indeks jest przydatny w przypadku zapytania, jeśli może zmniejszyć liczbę dokumentów, które silnik zapytań musi pobrać z pamięci podstawowej, lub jeśli kolejność pól może spełnić wymagania zapytania dotyczące sortowania.
Jeśli zapytanie korzysta z indeksu, ale silnik zapytań nadal pobiera i odrzuca wiele dokumentów (co można stwierdzić na podstawie węzła skanowania, który zwraca wiele rekordów, a następnie węzła 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 zapytanie korzysta z indeksu, ale mechanizm zapytań nadal wykonuje w pamięci ponowne porządkowanie zbioru wyników, co jest wskazywane przez węzeł MajorSort w drzewie wykonania zapytania, oznacza to, że użyty indeks nie może być używany do spełnienia wymagania sortowania zapytania. Aby utworzyć bardziej odpowiedni indeks, zapoznaj się z następną sekcją.
Tworzenie indeksów
Postępuj zgodnie z dokumentacją dotyczącą zarządzania indeksami, aby tworzyć indeksy. Aby mieć pewność, że zapytanie może korzystać z indeksów, utwórz zwykłe indeksy (nie Multikey) z polami w tej kolejności:
- Wszystkie pola, które będą używane w operatorach równości. Aby zmaksymalizować szansę ponownego użycia w różnych zapytaniach, uporządkuj pola w kolejności malejącej liczby wystąpień pól w operatorach równości w zapytaniach.
- Wszystkie pola, według których będzie sortowana tabela (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 będą zwracane w ramach zapytania w indeksie: uwzględnienie takich pól w indeksie umożliwia mu obsługę zapytania i uniknięcie pobierania dokumentu z pamięci podstawowej.
Wymuszanie skanowania indeksu lub tabeli
Gdy wysyłasz zapytanie Cloud Firestore, automatycznie używa ono indeksów, które prawdopodobnie zwiększą jego wydajność. Dzięki temu nie musisz określać indeksu w zapytaniach. W przypadku zapytań, które mają kluczowe znaczenie dla Twojego obciążenia, zalecamy jednak używanie opcji forceIndex, aby uzyskać bardziej spójną wydajność.
W niektórych przypadkach usługa Cloud Firestore może wybrać indeks, który spowoduje wzrost opóźnienia zapytania. Jeśli po wykonaniu czynności związanych z rozwiązywaniem problemów z regresją wydajności stwierdzisz, że warto wypróbować inny indeks dla zapytania, możesz go określić za pomocą opcji forceIndex.
W przypadku dowolnego etapu wprowadzania danych w operacjach potoku możesz użyć opcji forceIndex, aby zastąpić domyślny plan zapytania Cloud Firestore i określić indeks do użycia lub wymusić skanowanie tabeli.
Wymuszanie konkretnego indeksu
Aby wymusić użycie określonego indeksu w zapytaniu, podaj identyfikator indeksu jako ciąg tekstowy w opcji forceIndex. Identyfikator indeksu znajdziesz w konsoli lub w komunikatach o błędach.
W tym przykładzie wymuszamy użycie przez optymalizator 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 wymuszania konkretnego indeksu:
- testowanie skuteczności różnych indeksów,
- zapewnienie, że w przypadku zapytania używany jest konkretny, optymalny indeks;
- Zastępowanie optymalizatora, gdy jego domyślny wybór jest nieoptymalny w przypadku konkretnego zapytania.
Jeśli określony indeks nie zostanie znaleziony, zapytanie się nie powiedzie.
Wymuszanie skanowania tabeli
Skanowanie tabeli odczytuje dokumenty w kolekcji lub grupie kolekcji bez używania indeksów dodatkowych. Aby wymusić skanowanie tabeli, ustaw wartość 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:
- W przypadku bardzo małych kolekcji, w 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.
Używanie forceIndex z funkcją Wyjaśnienie zapytania
Za pomocą wyjaśnienia zapytania w trybach explain lub analyze możesz obserwować efekty działania forceIndex:
- Sprawdź, czy Cloud Firestore użył określonego indeksu w
forceIndex, sprawdzając identyfikator indeksu w węzłach liści drzewa wykonania. - Sprawdź, czy w planie pojawia się węzeł
TableScan, gdy używaszforceIndex: "primary". - W trybie
analyzeporównaj dane o skuteczności, takie jak opóźnienie, liczba skanowanych dokumentów i liczba skanowanych wpisów indeksu, z użyciem i bez użyciaforceIndex, aby dostroić wydajność zapytań.
Sprawdzone metody dotyczące forceIndex
forceIndex zapewnia większą kontrolę nad wykonywaniem zapytań, ale optymalizator zapytań w Cloud Firestore jest zwykle skuteczny w większości przypadków użycia.
Podczas korzystania z atrybutu forceIndex pamiętaj o tych sprawdzonych metodach:
- Korzystaj z
forceIndexrozważnie. Jeśli zauważysz, że domyślny plan zapytania nie zapewnia optymalnej wydajności, użyj funkcji Query Explain, aby zdiagnozować problem przed wymuszeniem indeksu. - Gdy używasz
forceIndex, testuj zapytania na realistycznych ilościach danych, aby poznać ich wydajność i charakterystykę kosztów. - Unikaj używania
forceIndex: "primary"w przypadku dużych kolekcji w środowiskach produkcyjnych.
Więcej informacji o wynikach zapytania wykonanego za pomocą funkcji Wyjaśnij zapytanie znajdziesz w artykule Informacje o wykonaniu zapytania.