„Query Explain“ verwenden

Mit Query Explain können Sie Abfragen im Datastore-Modus an das Back-End senden und detaillierte Leistungsstatistiken zur Ausführung von Back-End-Abfragen erhalten. Er funktioniert wie der EXPLAIN ANALYZE-Vorgang in vielen relationalen Datenbanksystemen.

Sie können Query Explain-Anfragen mit den Clientbibliotheken im Datastore-Modus senden.

Die Ergebnisse von „Query Explain“ helfen Ihnen zu verstehen, wie Ihre Abfragen ausgeführt werden. Sie zeigen Ineffizienzen auf und ermitteln mögliche serverseitige Engpässe.

Erläuterung der Suchanfrage:

  • Bietet Einblicke in die Planungsphase, damit Sie Ihre Abfrageindexe anpassen und die Effizienz steigern können.
  • Verschafft Ihnen einen Überblick über Kosten und Leistung auf Abfragebasis und ermöglicht Ihnen, schnell verschiedene Abfragemuster durchzugehen, um deren Nutzung zu optimieren.

Erläuterung der Optionen für Abfrageerklärung: Standard und Analyse

Query Explain-Vorgänge können mit der Option default oder Analyze ausgeführt werden.

Bei der Standardoption plant Query Explain die Abfrage, aber die Ausführungsphase wird übersprungen. Dadurch werden Informationen zur Planerphase zurückgegeben. So können Sie prüfen, ob eine Abfrage über die erforderlichen Indexe verfügt und welche Indexe verwendet werden. Auf diese Weise können Sie beispielsweise überprüfen, ob eine bestimmte Abfrage einen zusammengesetzten Index verwendet, anstatt sich über viele verschiedene Indexe hinweg zu überschneiden.

Mit der Analyseoption wird „Query Explain“ beide Pläne ausgeführt und die Abfrage ausgeführt. Dadurch werden alle zuvor genannten Planerinformationen sowie Statistiken aus der Ausführungslaufzeit der Abfrage zurückgegeben. Dazu gehören Abrechnungsinformationen sowie Informationen auf Systemebene über die Abfrageausführung. Sie können dieses Tool verwenden, um verschiedene Abfrage- und Indexkonfigurationen zu testen, um ihre Kosten und Latenz zu optimieren.

Was kostet „Query Explain“?

Wenn eine Abfrage mit der Standardoption erklärt wird, werden keine Index- oder Lesevorgänge ausgeführt. Unabhängig von der Komplexität der Abfrage wird ein Lesevorgang berechnet.

Wenn eine Abfrage mit der Analyseoption erklärt wird, werden Index- und Lesevorgänge ausgeführt, sodass Ihnen die Abfrage wie gewohnt in Rechnung gestellt wird. Für die Analyseaktivität fallen keine zusätzlichen Kosten an, sondern nur die üblichen Kosten für die Ausführung der Abfrage.

Abfrage mit der Standardoption ausführen

Sie können eine Clientbibliothek verwenden, um eine Anfrage für Standardoptionen zu senden.

Die Ergebnisse der Erläuterung werden beim Identity and Access Management authentifiziert, wobei dieselben Berechtigungen für reguläre Abfragevorgänge verwendet werden.

Java

Informationen zum Installieren und Verwenden der Clientbibliothek für den Datastore-Modus finden Sie unter Clientbibliotheken im Datastore-Modus. Weitere Informationen finden Sie in der Referenzdokumentation zur Java API im Datastore-Modus.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich im Datastore-Modus zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.


import com.google.cloud.datastore.Datastore;
import com.google.cloud.datastore.DatastoreOptions;
import com.google.cloud.datastore.Entity;
import com.google.cloud.datastore.Query;
import com.google.cloud.datastore.QueryResults;
import com.google.cloud.datastore.models.ExplainMetrics;
import com.google.cloud.datastore.models.ExplainOptions;
import com.google.cloud.datastore.models.PlanSummary;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class QueryProfileExplain {
  public static void invoke() throws Exception {
    // Instantiates a client
    Datastore datastore = DatastoreOptions.getDefaultInstance().getService();

    // Build the query
    Query<Entity> query = Query.newEntityQueryBuilder().setKind("Task").build();

    // Set the explain options to get back *only* the plan summary
    QueryResults<Entity> results = datastore.run(query, ExplainOptions.newBuilder().build());

    // Get the explain metrics
    Optional<ExplainMetrics> explainMetrics = results.getExplainMetrics();
    if (!explainMetrics.isPresent()) {
      throw new Exception("No explain metrics returned");
    }
    PlanSummary planSummary = explainMetrics.get().getPlanSummary();
    List<Map<String, Object>> indexesUsed = planSummary.getIndexesUsed();
    System.out.println("----- Indexes Used -----");
    indexesUsed.forEach(map -> map.forEach((key, val) -> System.out.println(key + ": " + val)));
  }
}

Informationen zu den im Abfrageplan verwendeten Indexen finden Sie im Feld indexes_used in der Antwort:

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

Weitere Informationen zum Bericht finden Sie in der Referenz zum Bericht.

Abfrage mit der Analyseoption ausführen

Sie können eine Clientbibliothek verwenden, um eine Anfrage für Standardoptionen zu senden.

Die Ergebnisse der Abfrageergebnisse werden mit der Identitäts- und Zugriffsverwaltung (IAM) authentifiziert, wobei dieselben Berechtigungen für reguläre Abfragevorgänge verwendet werden.

Java

Informationen zum Installieren und Verwenden der Clientbibliothek für den Datastore-Modus finden Sie unter Clientbibliotheken im Datastore-Modus. Weitere Informationen finden Sie in der Referenzdokumentation zur Java API im Datastore-Modus.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich im Datastore-Modus zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

import com.google.cloud.datastore.Datastore;
import com.google.cloud.datastore.DatastoreOptions;
import com.google.cloud.datastore.Entity;
import com.google.cloud.datastore.Query;
import com.google.cloud.datastore.QueryResults;
import com.google.cloud.datastore.models.ExecutionStats;
import com.google.cloud.datastore.models.ExplainMetrics;
import com.google.cloud.datastore.models.ExplainOptions;
import com.google.cloud.datastore.models.PlanSummary;
import java.util.List;
import java.util.Map;

public class QueryProfileExplainAnalyze {
  public static void invoke() throws Exception {
    // Instantiates a client
    Datastore datastore = DatastoreOptions.getDefaultInstance().getService();

    // Build the query
    Query<Entity> query = Query.newEntityQueryBuilder().setKind("Task").build();

    // Set explain options with analzye = true to get back the query stats, plan info, and query
    // results
    QueryResults<Entity> results =
        datastore.run(query, ExplainOptions.newBuilder().setAnalyze(true).build());

    // Get the result set stats
    if (!results.getExplainMetrics().isPresent()) {
      throw new Exception("No explain metrics returned");
    }
    ExplainMetrics explainMetrics = results.getExplainMetrics().get();

    // Get the execution stats
    if (!explainMetrics.getExecutionStats().isPresent()) {
      throw new Exception("No execution stats returned");
    }

    ExecutionStats executionStats = explainMetrics.getExecutionStats().get();
    Map<String, Object> debugStats = executionStats.getDebugStats();
    System.out.println("----- Debug Stats -----");
    debugStats.forEach((key, val) -> System.out.println(key + ": " + val));
    System.out.println("----------");

    long resultsReturned = executionStats.getResultsReturned();
    System.out.println("Results returned: " + resultsReturned);

    // Get the plan summary
    PlanSummary planSummary = explainMetrics.getPlanSummary();
    List<Map<String, Object>> indexesUsed = planSummary.getIndexesUsed();
    System.out.println("----- Indexes Used -----");
    indexesUsed.forEach(map -> map.forEach((key, val) -> System.out.println(key + ": " + val)));

    if (!results.hasNext()) {
      throw new Exception("query yielded no results");
    }

    // Get the query results
    System.out.println("----- Query Results -----");
    while (results.hasNext()) {
      Entity entity = results.next();
      System.out.printf("Entity: %s%n", entity);
    }
  }
}

Im Objekt executionStats finden Sie Informationen zur Abfrageprofilerstellung, z. B.:

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

Weitere Informationen zum Bericht finden Sie in der Referenz zum Bericht.

Ergebnisse interpretieren und Anpassungen vornehmen

Im folgenden Beispielszenario werden Filme nach Genre und Produktionsland abgefragt und veranschaulicht, wie die von der Abfrage verwendeten Indexe optimiert werden.

Weitere Informationen zum Bericht finden Sie in der Referenz zum Bericht „Query Explain“.

Nehmen wir zur Veranschaulichung die Entsprechung dieser SQL-Abfrage an.

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

Mit der Option „Analysieren“ wird in der folgenden Berichtsausgabe angezeigt, wie die Abfrage für die Einzelfeldindexe (category ASC, __name__ ASC) und (country ASC, __name__ ASC) ausgeführt wird. Sie scannt 16.500 Indexeinträge, gibt aber nur 1.200 Dokumente zurück.

// Output query planning info
"indexes_used": [
    {"query_scope": "Collection Group", "properties": "(category ASC, __name__ ASC)"},
    {"query_scope": "Collection Group", "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",
               }
    }
}

Um die Leistung beim Ausführen der Abfrage zu optimieren, können Sie einen vollständig abgedeckten zusammengesetzten Index erstellen (Kategorie ASC, Land ASC, __name__ ASC).

Wenn Sie die Abfrage noch einmal im Analysemodus ausführen, sehen Sie, dass der neu erstellte Index für diese Abfrage ausgewählt ist und die Abfrage viel schneller und effizienter ausgeführt wird.

// Output query planning info
    "indexes_used": [
        {"query_scope": "Collection Group", "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",
               }
    }
}

Nächste Schritte