„Query Explain“ verwenden

Mit Query Explain können Sie Abfragen im Datastore-Modus an das Back-End senden und erhalten im Gegenzug detaillierte Leistungsstatistiken zur Back-End-Abfrageausführung. Die Funktion ähnelt dem Vorgang EXPLAIN ANALYZE in vielen relationalen Datenbanksystemen.

Sie können Query Explain-Anfragen mit den Clientbibliotheken für den Datastore-Modus senden.

Die Ergebnisse von Query Explain helfen Ihnen, die Ausführung Ihrer Abfragen zu verstehen. Sie zeigen Ineffizienzen und den Ort wahrscheinlicher serverseitiger Engpässe.

Query Explain:

  • Bietet Einblicke in die Planungsphase, damit Sie Ihre Abfrageindexe anpassen und die Effizienz steigern können.
  • Hilft Ihnen, Ihre Kosten und Leistung pro Abfrage zu verstehen, und ermöglicht es Ihnen, schnell verschiedene Abfragemuster zu durchlaufen, um ihre Nutzung zu optimieren.

Optionen von Query Explain: „default“ und „analyze“

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

Mit der Option „default“ plant Query Explain die Abfrage, überspringt aber die Ausführungsphase. Dadurch werden Informationen zur Planungsphase zurückgegeben. Sie können damit prüfen, ob eine Abfrage die erforderlichen Indexe hat, und feststellen, welche Indexe verwendet werden. So können Sie beispielsweise prüfen, ob eine bestimmte Abfrage einen zusammengesetzten Index verwendet, anstatt viele verschiedene Indexe zu schneiden.

Mit der Option „analyze“ plant und führt Query Explain die Abfrage aus. Dadurch werden alle zuvor erwähnten Informationen zur Planungsphase zusammen mit Statistiken aus der Abfrageausführungszeit zurückgegeben. Dazu gehören Abrechnungsinformationen sowie Einblicke auf Systemebene in die Abfrageausführung. Mit diesem Tool können Sie verschiedene Abfrage- und Indexkonfigurationen testen, um Kosten und Latenz zu optimieren.

Was kostet Query Explain?

Wenn eine Abfrage mit der Option „default“ erklärt wird, werden keine Index- oder Lesevorgänge ausgeführt. Unabhängig von der Komplexität der Abfrage wird ein Lesevorgang in Rechnung gestellt.

Wenn eine Abfrage mit der Option „analyze“ erklärt wird, werden Index- und Lesevorgänge ausgeführt. Daher werden Ihnen die Kosten für die Abfrage wie gewohnt in Rechnung gestellt. 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 Option „default“ ausführen

Sie können eine Clientbibliothek verwenden, um eine Anfrage mit der Option „default“ zu senden.

Die Ergebnisse von Query Explain werden mit Identity and Access Management authentifiziert. Dabei werden dieselben Berechtigungen wie für reguläre Abfragevorgänge verwendet.

Java

Informationen zum Installieren und Verwenden der Clientbibliothek für den Datastore-Modus finden Sie hier: Datastore mode client libraries. Weitere Informationen finden Sie in der Referenzdokumentation zur Datastore Mode Java API.

Richten Sie die Standardanmeldedaten für Anwendungen ein, um sich beim 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)));
  }
}

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

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

Weitere Informationen zum Bericht finden Sie unter der Berichtsreferenz.

Abfrage mit der Option „analyze“ ausführen

Sie können eine Clientbibliothek verwenden, um eine Anfrage mit der Option „default“ zu senden.

Die Ergebnisse von Query Explain werden mit Identity and Access Management (IAM) authentifiziert. Dabei werden dieselben Berechtigungen wie für reguläre Abfragevorgänge verwendet.

Java

Informationen zum Installieren und Verwenden der Clientbibliothek für den Datastore-Modus finden Sie hier: Datastore mode client libraries. Weitere Informationen finden Sie in der Referenzdokumentation zur Datastore Mode Java API.

Richten Sie die Standardanmeldedaten für Anwendungen ein, um sich beim 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 unter der Berichtsreferenz.

Ergebnisse interpretieren und Anpassungen vornehmen

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

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

Nehmen wir zur Veranschaulichung die folgende SQL-Abfrage an.

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

Wenn wir die Option „analyze“ verwenden, zeigt die folgende Berichtsausgabe, dass die Abfrage für Einzelfeldindexe (category ASC, __name__ ASC) und (country ASC, __name__ ASC) ausgeführt wird. Es werden 16.500 Indexeinträge gescannt, aber nur 1.200 Dokumente zurückgegeben.

// 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 bei der Ausführung der Abfrage zu optimieren, können Sie einen vollständig abgedeckten zusammengesetzten Index erstellen: (category ASC, country ASC, __name__ ASC).

Wenn wir die Abfrage noch einmal im Analysemodus ausführen, sehen wir, dass der neu erstellte Index für diese Abfrage ausgewählt wurde 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