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 działania funkcji Query Explain pomagają zrozumieć, jak są wykonywane zapytania, wskazując nieefektywne miejsca 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ślne 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 on 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 o planiście wraz ze statystykami dotyczącymi 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ą

Aby przesłać prośbę o ustawienie domyślne, możesz użyć bibliotek klienta.

Pamiętaj, że żądania są uwierzytelniane za pomocą usługi IAM, przy użyciu 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ć na format 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.

Używanie narzędzia Query Explain z opcją analizy

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

Pamiętaj, że żądania są uwierzytelniane za pomocą usługi IAM, przy użyciu 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().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 takim kształcie.

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",
               }
    }
}