Comprendere il rendimento delle query utilizzando la spiegazione delle query

Query Explain ti consente di inviare query Cloud Firestore al backend e di ricevere in cambio statistiche dettagliate sul rendimento dell'esecuzione delle query del backend. Funziona come l'operazione EXPLAIN [ANALYZE] in molti sistemi di database relazionali.

Le richieste di spiegazione delle query possono essere inviate utilizzando le librerie client del server Firestore.

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 approfondimenti sulla fase di pianificazione delle query per consentirti di modificare gli indici delle query e aumentare l'efficienza.
  • L'utilizzo dell'opzione di analisi ti aiuta a comprendere i costi e le prestazioni su base query e ti consente di eseguire rapidamente l'iterazione di diversi pattern di query 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 salta la fase di esecuzione. Verranno restituite le informazioni sulla fase del pianificatore. 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 molti indici diversi.

Con l'opzione di analisi, Query Explain genera entrambi i piani ed esegue la query. Verranno restituite tutte le informazioni del pianificatore menzionate in precedenza, insieme alle statistiche del runtime di esecuzione della query. Saranno inclusi i dati di fatturazione della query, nonché approfondimenti a livello di sistema sull'esecuzione della query. Puoi utilizzare questi strumenti per testare varie configurazioni di query e indici al fine di ottimizzarne il costo e la latenza.

Quanto costa Query Explain?

Quando utilizzi Spiega query con l'opzione predefinita, non vengono eseguite operazioni di indice o lettura. Indipendentemente dalla complessità della query, viene addebitata un'operazione di lettura.

Quando utilizzi la spiegazione della query con l'opzione di analisi, vengono eseguite operazioni di indicizzazione e lettura, pertanto ti viene addebitato il costo della query come di consueto. Non è previsto alcun costo aggiuntivo per l'attività di analisi, solo l'importo consueto per la query in esecuzione.

Utilizzare Spiega query con l'opzione predefinita

Puoi utilizzare le librerie client per inviare una richiesta di opzione predefinita.

Tieni presente che le richieste vengono autenticate con IAM, utilizzando le stesse autorizzazioni per le normali operazioni di query. Altre tecniche di autenticazione, come Firebase Authentication, vengono ignorate. Per ulteriori informazioni, consulta la guida sull'IAM per le librerie client del server.

Java (amministratore)

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

    
Nodo (amministratore)

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;

    

Il formato esatto della risposta dipende dall'ambiente di esecuzione. I risultati restituiti possono essere convertiti in JSON. Ad esempio:

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

Per ulteriori informazioni, consulta la sezione Riferimento al report Spiega query.

Utilizzare Spiega query con l'opzione Analizza

Puoi utilizzare le librerie client per inviare una richiesta di opzione di analisi.

Tieni presente che le richieste vengono autenticate con IAM, utilizzando le stesse autorizzazioni per le normali operazioni di query. Altre tecniche di autenticazione, come Firebase Authentication, vengono ignorate. Per ulteriori informazioni, consulta la guida sull'IAM per le librerie client del server.

Java (amministratore)

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

    
Nodo (amministratore)

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;

    

L'esempio seguente mostra l'oggetto stats restituito oltre a planInfo. Il formato esatto della risposta dipende dall'ambiente di esecuzione. La risposta di esempio è in formato 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",
               }
    }

}

Per ulteriori informazioni, consulta la sezione Riferimento al report Spiega query.

Interpreta i risultati e apporta aggiustamenti

Vediamo uno scenario di esempio in cui eseguiamo query sui film per genere e paese di produzione.

A titolo esemplificativo, ipotizza l'equivalente di questa query SQL.

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

Se utilizziamo l'opzione di analisi, le metriche restituite mostrano che la query viene eseguita su due 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", "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",
               }
    }
}

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

Eseguendo di nuovo la query con l'opzione di analisi, possiamo vedere che l'indice appena creato è selezionato per questa query, che viene eseguita molto più velocemente e in modo più efficiente.

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