Poznawanie wydajności zapytań za pomocą funkcji Query Explain

Query Explain umożliwia przesyłanie zapytań Cloud Firestore do zaplecza i otrzymywanie szczegółowych statystyk wydajności dotyczących wykonywania zapytań na zapleczu. Działa ona podobnie jak operacja EXPLAIN [ANALYZE] w wielu relacyjnych systemach baz danych.

Żądania wyjaśnienia zapytania można wysyłać za pomocą bibliotek klienta serwera Firestore.

Wyniki analizy zapytań pomagają zrozumieć, jak są wykonywane zapytania, wskazując nieefektywne rozwiązania i lokalizację prawdopodobnych wąskich gardeł po stronie serwera.

Wyjaśnienie zapytania:

  • Udostępnia statystyki dotyczące fazy planowania zapytania, dzięki czemu możesz dostosowywać indeksy zapytań i zwiększać wydajność.
  • Korzystając z opcji analizy, możesz poznać koszty i wydajność poszczególnych zapytań oraz szybko przeglądać różne wzorce zapytań, aby zoptymalizować ich użycie.

Opisywanie zapytań: domyślna i analiza

Operacje Query Explain można wykonywać, korzystając z opcji domyślnej lub analizowania.

W przypadku opcji domyślnej Query Explain planuje zapytanie, ale pomija etap wykonania. Zwróci ona informacje o etapie planowania. Możesz go użyć, aby sprawdzić, czy zapytanie ma niezbędne indeksy i które indeksy są używane. Dzięki temu możesz na przykład sprawdzić, czy dane zapytanie korzysta z indeksu złożonego zamiast przecięcia wielu różnych indeksów.

W przypadku opcji analizy Query Explain planuje i wykonuje zapytanie. Zwraca ona wszystkie wspomniane wcześniej informacje z planisty oraz statystyki dotyczące czasu wykonywania zapytania. Zawierać będzie informacje rozliczeniowe dotyczące zapytania oraz statystyki dotyczące jego wykonania na poziomie systemu. Za pomocą tych narzędzi możesz testować różne konfiguracje zapytań i indeksów, aby zoptymalizować ich koszt i opóźnienie.

Ile kosztuje Query Explain?

Gdy używasz opcji domyślnej Query Explain, nie są wykonywane żadne operacje indeksowania ani odczytu. Niezależnie od złożoności zapytania naliczana jest jedna operacja odczytu.

Gdy używasz Query Explain z opcją analizy, operacje indeksowania i odczytywania są wykonywane, więc zapytanie jest obciążone opłatą jak zwykle. Analiza nie wiąże się z dodatkowymi opłatami, tylko z zwykłymi opłatami za wykonywane zapytania.

Korzystanie z Query Explain z opcją domyślną

Możesz użyć bibliotek klienta, aby przesłać prośbę o domyślną opcję.

Pamiętaj, że żądania są uwierzytelniane za pomocą usługi IAM, która używa tych samych uprawnień co w przypadku zwykłych operacji zapytań. Inne metody uwierzytelniania, takie jak Firebase Authentication, są ignorowane. Więcej informacji znajdziesz w przewodniku Zarządzanie tożsamością w przypadku bibliotek klienta na serwerze.

Java (Administracja)

Query q = db.collection("col").whereGreaterThan("a", 1);
ExplainOptions options = ExplainOptions.builder().build();

ExplainResults<QuerySnapshot> explainResults = q.explain(options).get();
ExplainMetrics metrics = explainResults.getMetrics();
PlanSummary planSummary = metrics.getPlanSummary();

    
Węzeł (Administracja)

const q = db.collection('col').where('country', '=', 'USA');
const options = { analyze : 'false' };

const explainResults = await q.explain(options);

const metrics = explainResults.metrics;
const plan = metrics.planSummary;

    

Dokładny format odpowiedzi zależy od środowiska wykonania. Zwrócone wyniki można przekonwertować do formatu JSON. Przykład:

{
    "indexes_used": [
        {"query_scope": "Collection", "properties": "(category ASC, __name__ ASC)"},
        {"query_scope": "Collection", "properties": "(country ASC, __name__ ASC)"},
    ]
}

Więcej informacji znajdziesz w dokumentacji dotyczącej raportu Query Explain.

Korzystanie z Query Explain z opcją analizy

Za pomocą bibliotek klienta możesz przesłać prośbę o analizę opcji.

Pamiętaj, że żądania są uwierzytelniane za pomocą usługi IAM, która używa tych samych uprawnień co w przypadku zwykłych operacji zapytań. Inne techniki uwierzytelniania, takie jak Firebase Authentication, są ignorowane. Więcej informacji znajdziesz w przewodniku Zarządzanie tożsamością w przypadku bibliotek klienta na serwerze.

Java (Administracja)

Query q = db.collection("col").whereGreaterThan("a", 1);

ExplainOptions options = ExplainOptions.builder().setAnalyze(true).build();

ExplainResults<QuerySnapshot> explainResults = q.explain(options).get();

ExplainMetrics metrics = explainResults.getMetrics();
PlanSummary planSummary = metrics.getPlanSummary();
List<Map<String, Object>> indexesUsed = planSummary.getIndexesUsed();
ExecutionStats stats = metrics.getExecutionStats();

    
Węzeł (Administracja)

const q = db.collection('col').where('country', '=', 'USA');

const options = { analyze : 'true' };

const explainResults = await q.explain(options);

const metrics = explainResults.metrics;
const plan = metrics.planSummary;
const indexesUsed = plan.indexesUsed;
const stats = metrics.executionStats;

    

Poniższy przykład pokazuje, że oprócz obiektu planInfo zwracany jest też obiekt stats. Dokładny format odpowiedzi zależy od środowiska wykonania. Przykładowa odpowiedź jest w formacie JSON.

{
    "resultsReturned": "5",
    "executionDuration": "0.100718s",
    "readOperations": "5",
    "debugStats": {
               "index_entries_scanned": "95000",
               "documents_scanned": "5"
               "billing_details": {
                     "documents_billable": "5",
                     "index_entries_billable": "0",
                     "small_ops": "0",
                     "min_query_cost": "0",
               }
    }

}

Więcej informacji znajdziesz w dokumentacji dotyczącej raportu Query Explain.

Interpretowanie wyników i wprowadzanie zmian

Przyjrzyjmy się przykładowemu scenariuszowi, w którym wysyłamy zapytanie o filmy według gatunku i kraju produkcji.

Dla przykładu przyjmij zapytanie SQL o takiej treści:

SELECT *
FROM /movies
WHERE category = 'Romantic' AND country = 'USA';

Jeśli użyjemy opcji analizy, zwrócone dane wskazują, że zapytanie jest wykonywane na 2 indek sach pojedynczego pola: (category ASC, __name__ ASC)(country ASC, __name__ ASC). Skanuje 16 500 wpisów w indeksie, ale zwraca tylko 1200 dokumentów.

// Output query planning info
{
    "indexes_used": [
        {"query_scope": "Collection", "properties": "(category ASC, __name__ ASC)"},
        {"query_scope": "Collection", "properties": "(country ASC, __name__ ASC)"},
    ]
}

// Output query status
{
    "resultsReturned": "1200",
    "executionDuration": "0.118882s",
    "readOperations": "1200",
    "debugStats": {
               "index_entries_scanned": "16500",
               "documents_scanned": "1200"
               "billing_details": {
                     "documents_billable": "1200",
                     "index_entries_billable": "0",
                     "small_ops": "0",
                     "min_query_cost": "0",
               }
    }
}

Aby zoptymalizować wydajność wykonywania zapytania, możesz utworzyć indeks złożony w pełni pokryty (category ASC, country ASC, __name__ ASC).

Po ponownym uruchomieniu zapytania z opcją analizy widzimy, że wybrany został nowo utworzony indeks, a zapytanie jest wykonywane znacznie szybciej i efektywniej.

// Output query planning info
{
    "indexes_used": [
        {"query_scope": "Collection", "properties": "(category ASC, country ASC,  __name__ ASC)"}
    ]
}

// Output query stats
{
    "resultsReturned": "1200",
    "executionDuration": "0.026139s",
    "readOperations": "1200",
    "debugStats": {
               "index_entries_scanned": "1200",
               "documents_scanned": "1200"
               "billing_details": {
                     "documents_billable": "1200",
                     "index_entries_billable": "0",
                     "small_ops": "0",
                     "min_query_cost": "0",
               }
    }
}