Utilizzare Query Explain

Query Explain consente di inviare query in modalità Datastore al backend e ricevere statistiche dettagliate sulle prestazioni nell'esecuzione delle query al backend in cambio. Funziona come l'operazione EXPLAIN ANALYZE in molte sistemi di database relazionale.

Puoi inviare richieste Query Explain utilizzando Librerie client in modalità Datastore.

I risultati di Query Explain ti aiutano a capire come vengono eseguite le query, mostrandoti le inefficienze e la posizione di probabili colli di bottiglia lato server.

Spiegazione della query:

  • Fornisce insight sulla fase di pianificazione, in modo da poter modificare gli indici delle query e aumentare l'efficienza.
  • Ti aiuta a comprendere costi e prestazioni per query e consente di eseguire rapidamente l'iterazione di diversi pattern di query per per ottimizzarne l'utilizzo.

Informazioni sulle opzioni di spiegazione della query: predefinita e analisi

Le operazioni di spiegazione delle query possono essere eseguite utilizzando l'opzione predefinita o analizza.

Con l'opzione predefinita, Query Explain pianifica la query, ma ignora durante la fase di esecuzione. Verranno restituite le informazioni sulla fase dello strumento di pianificazione. Puoi utilizzarlo per verificare che una query abbia gli indici necessari e capire quali vengono utilizzati. In questo modo, ad esempio, puoi verificare che una determinata query utilizzi un indice composto anziché dover eseguire l'intersezione di più indici diversi.

Con l'opzione di analisi, Query Spiega sia i piani sia l'esecuzione query. Verranno restituite tutte le informazioni del pianificatore menzionate in precedenza, insieme alle statistiche del runtime dell'esecuzione della query. Saranno inclusi i dati di fatturazione e approfondimenti a livello di sistema sull'esecuzione delle query. Puoi utilizzare la modalità questo strumento per testare varie configurazioni di query e indici per a ottimizzare costi e latenza.

Quanto costa Query Explain?

Quando una query è spiegata con l'opzione predefinita, nessun indice o tutte le operazioni eseguite. Indipendentemente dalla complessità della query, viene addebitata un'operazione di lettura.

Quando una query viene spiegata con l'opzione Analizza, indicizza e leggi operazioni vengono eseguite, quindi la query ti viene addebitata come di consueto. Non è previsto alcun costo aggiuntivo per l'attività di analisi, ma solo l'importo consueto per la query in esecuzione.

Esegui una query con l'opzione predefinita

Puoi utilizzare una libreria client per inviare una richiesta di opzione predefinita.

Tieni presente che i risultati della spiegazione della query vengono autenticati con Identity and Access Management, utilizzando le stesse autorizzazioni per le normali operazioni di query.

Java

Per scoprire come installare e utilizzare la libreria client per la modalità Datastore, consulta Librerie client per la modalità Datastore. Per ulteriori informazioni, consulta la documentazione di riferimento dell'API Java in modalità Datastore.

Per autenticarti alla modalità Datastore, configura le credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.


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)));
  }
}

Visualizza il campo indexes_used nella risposta per scoprire di più sugli indici utilizzato nel piano di query:

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

Per ulteriori informazioni sul report, consulta il riferimento del report.

Esegui una query con l'opzione di analisi

Puoi utilizzare una libreria client per inviare una richiesta di opzione predefinita.

Tieni presente che i risultati dell'analisi delle query vengono autenticati con Identity and Access Management (IAM). usando le stesse autorizzazioni per le normali operazioni di query.

Java

Per scoprire come installare e utilizzare la libreria client per la modalità Datastore, consulta Librerie client per la modalità Datastore. Per ulteriori informazioni, consulta API Java della modalità Datastore documentazione di riferimento.

Per autenticarti alla modalità Datastore, configura le credenziali predefinite dell'applicazione. Per ulteriori informazioni, vedi Configura l'autenticazione per un ambiente di sviluppo locale.

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);
    }
  }
}

Visualizza l'oggetto executionStats per trovare le informazioni di profilazione delle query, ad esempio:

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

Per ulteriori informazioni sul report, consulta il riferimento del report.

Interpretare i risultati e apportare le modifiche

Lo scenario di esempio che segue esegue query per i film per genere e paese di produzione e dimostra come ottimizzare gli indici utilizzati query.

Per ulteriori informazioni sul report, consulta la documentazione di riferimento del report Spiega query.

Ad esempio, supponiamo che l'equivalente di questa query SQL.

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

Se utilizziamo l'opzione Analizza, il seguente output del report mostra che la query viene eseguita sugli indici a campo singolo (category ASC, __name__ ASC) e (country ASC, __name__ ASC). Scansiona 16.500 voci dell'indice, ma restituisce solo 1200 documenti.

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

Per ottimizzare le prestazioni dell'esecuzione della query, puoi creare un indice composito completamente coperto (categoria ASC, paese ASC, __name__ ASC).

Eseguendo di nuovo la query in modalità di analisi, possiamo vedere che l'indice appena creato è selezionato per questa query, che viene eseguita molto più velocemente ed efficacemente.

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

Passaggi successivi