Durata di una query Spanner

Client

Spanner supporta le query SQL. Ecco una query di esempio:

SELECT s.SingerId, s.FirstName, s.LastName, s.SingerInfo
FROM Singers AS s
WHERE s.FirstName = @firstName;

Il costrutto @firstName è un riferimento a un parametro di query. Puoi usare un parametro di query ovunque sia possibile utilizzare un valore letterale. È vivamente consigliato utilizzare i parametri nelle API programmatiche. L'utilizzo dei parametri di ricerca consente di evitare attacchi di iniezione SQL e le query risultanti hanno maggiori probabilità di trarre vantaggio da varie cache lato server. Vedi Memorizzazione nella cache di seguito.

I parametri di query devono essere associati a un valore al momento dell'esecuzione della query. Ad esempio:

Statement statement =
    Statement.newBuilder("SELECT s.SingerId...").bind("firstName").to("Jimi").build();
try (ResultSet resultSet = dbClient.singleUse().executeQuery(statement)) {
 while (resultSet.next()) {
 ...
 }
}

Quando Spanner riceve una chiamata API, analizza la query e i parametri associati per determinare quale nodo server Spanner deve elaborare la query. Il server restituisce un flusso di righe di risultati utilizzate dalle chiamate a ResultSet.next().

Esecuzione della query

L'esecuzione della query inizia con l'arrivo di una richiesta "esegui query" su un server Spanner. Il server esegue le seguenti operazioni:

  • Convalida la richiesta
  • Analizza il testo della query
  • Generare un'algebra delle query iniziale
  • Generare un'algebra delle query ottimizzata
  • Genera un piano di query eseguibile
  • Eseguire il piano (controllare le autorizzazioni, leggere i dati, codificare i risultati e così via).

Diagramma di flusso di esecuzione della query che mostra client, server radice e server foglia

Analisi

Il parser SQL analizza il testo della query e lo converte in una struttura ad albero della sintassi astratta. Estrae la struttura di base delle query (SELECT … FROM … WHERE …) ed esegue controlli sintattici.

Algebra

Il sistema dei tipi di Spanner può rappresentare scalari, array, strutture e così via. L'algebra delle query definisce gli operatori per le scansioni delle tabelle, i filtri, l'ordinamento/raggruppamento, tutti i tipi di join, l'aggregazione e molto altro ancora. L'algebra iniziale delle query viene creata dall'output del parser. I riferimenti ai nomi di campo nell'albero di analisi vengono risolti utilizzando lo schema del database. Questo codice verifica anche la presenza di errori semantici (ad es. numero errato di parametri, mancata corrispondenza del tipo e così via).

Il passaggio successivo ("ottimizzazione della query") prende l'algebra iniziale e genera un'algebra più ottimale. Potrebbe essere più semplice, più efficiente o semplicemente più adatto alle funzionalità del motore di esecuzione. Ad esempio, l'algebra iniziale potrebbe specificare solo un "join", mentre l'algebra ottimizzata specifica un "hash join".

Esecuzione

Il piano di query eseguibile finale viene creato a partire dall'algebra riscritta. In sostanza, il piano eseguibile è un grafo diretto aciclico di "iteratori". Ogni iteratore espone una sequenza di valori. Gli iteratori possono consumare input per produrre output (ad es. ordinare l'iteratore). Le query che prevedono un singolo split possono essere eseguite da un singolo server (quello che contiene i dati). Il server eseguirà la scansione di intervalli da varie tabelle, eseguirà i join, eseguirà l'aggregazione e tutte le altre operazioni definite dall'algebra delle query.

Le query che prevedono più suddivisioni verranno fattorizzate in più parti. Alcune parti della query continueranno a essere eseguite sul server principale (principale). Altre sottoquery parziali vengono consegnate ai nodi foglia, ovvero quelli proprietari delle suddivisioni lette. Questo trasferimento può essere applicato in modo ricorsivo per query complesse, il che genera una struttura di esecuzioni del server. Tutti i server concordano su un timestamp in modo che i risultati della query siano uno snapshot coerente dei dati. Ogni server foglia restituisce un flusso di risultati parziali. Per le query che prevedono l'aggregazione, questi potrebbero essere risultati parzialmente aggregati. Il server radice di query elabora i risultati dei server foglia ed esegue il resto del piano di query. Per maggiori informazioni, consulta Piani di esecuzione delle query.

Quando una query prevede più suddivisioni, Spanner può eseguirla in parallelo tra le suddivisioni. Il grado di parallelismo dipende dall'intervallo di dati analizzati dalla query, dal piano di esecuzione delle query e dalla distribuzione dei dati tra le suddivisioni. Spanner imposta automaticamente il grado massimo di parallelismo per una query in base alle dimensioni dell'istanza e alla configurazione dell'istanza (una o più regioni) al fine di ottenere prestazioni ottimali per le query ed evitare il sovraccarico della CPU.

Memorizzazione nella cache

Molti degli artefatti dell'elaborazione delle query vengono automaticamente memorizzati nella cache e riutilizzati per query successive. Sono incluse algebre di query, piani di query eseguibili e così via. La memorizzazione nella cache si basa sul testo delle query, sui nomi, sui tipi di parametri associati e così via. Questo è il motivo per cui è preferibile utilizzare parametri associati (come @firstName nell'esempio sopra) anziché valori letterali nel testo della query. La versione precedente può essere memorizzata nella cache una volta e riutilizzata indipendentemente dal valore effettivo del limite. Per ulteriori dettagli, consulta Ottimizzazione delle prestazioni delle query di Spanner.

Gestione degli errori

Il flusso di righe di risultati del metodo executeQuery può essere interrotto per qualsiasi motivo: errori di rete temporanei, trasferimento di una suddivisione da un server a un altro (ad esempio, bilanciamento del carico), riavvii del server (ad es. l'upgrade a una nuova versione) e così via. Per facilitare il ripristino da questi errori, Spanner invia "riprendi token" opachi insieme a batch di risultati parziali Questi token curriculum possono essere utilizzati quando si riprova a eseguire la query per continuare dal punto in cui la query interrotta è stata interrotta. Se utilizzi le librerie client Spanner, questa operazione viene eseguita automaticamente, quindi gli utenti della libreria client non devono preoccuparsi di questo tipo di errore temporaneo.