Durata di una query Spanner

Client

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

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 utilizzare un parametro di query ovunque sia possibile utilizzare un valore letterale. Ti consigliamo vivamente di utilizzare i parametri nelle API programmatiche. L'utilizzo dei parametri di ricerca consente di evitare gli attacchi di iniezione SQL e le query risultanti hanno maggiori probabilità di trarre vantaggio da varie cache lato server. Consulta la sezione Memorizzazione nella cache di seguito.

I parametri di query devono essere associati a un valore durante l'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 questi passaggi:

  • Convalida la richiesta
  • Analizza il testo della query
  • Generare un'algebra di query iniziale
  • Genera 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 relativo all'esecuzione della query che mostra client, server radice e server foglia

Analisi in corso...

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

Algebra

Il sistema di 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 delle query iniziale viene creata dall'output del parser. I riferimenti ai nomi dei campi 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, errori di 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 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. Fondamentalmente, il piano eseguibile è un grafico diretto aciclico di "iteratori". Ogni iteratore espone una sequenza di valori. Gli iteratori possono consumare input per produrre output (ad es. ordinamento iteratore). Le query che prevedono una singola suddivisione possono essere eseguite da un singolo server (quello che contiene i dati). Il server eseguirà la scansione di intervalli da varie tabelle, eseguirà join, eseguirà l'aggregazione e tutte le altre operazioni definite dall'algebra delle query.

Le query che prevedono più suddivisioni verranno suddivise in più parti. Alcune parte della query continueranno a essere eseguite sul server principale (root). Altre sottoquery parziali vengono trasferite ai nodi foglia (quelli che possiedono le suddivisioni che vengono lette). Questo passaggio può essere applicato in modo ricorsivo a query complesse, generando 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 implicano l'aggregazione, questi potrebbero essere risultati aggregati parzialmente. Il server radice delle query elabora i risultati dai server foglia ed esegue la parte restante del piano di query. Per maggiori informazioni, consulta Piani di esecuzione delle query.

Quando una query prevede più suddivisioni, Spanner può eseguire la query in parallelo tra le suddivisioni. Il grado di parallelismo dipende dall'intervallo di dati analizzati dalla query, dal piano di esecuzione della 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 (regionale o multiregionale) per ottenere prestazioni ottimali delle query ed evitare sovraccaricare la CPU.

Memorizzazione nella cache

Molti degli artefatti dell'elaborazione delle query vengono automaticamente memorizzati nella cache e riutilizzati per le query successive. Sono inclusi l'algebra delle query, i 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 è meglio utilizzare parametri associati (come @firstName nell'esempio precedente) che utilizzare valori letterali nel testo della query. L'utente precedente può essere memorizzato nella cache una volta e riutilizzato a prescindere dal valore effettivo associato. Per ulteriori dettagli, consulta Ottimizzazione delle prestazioni delle query di Spanner.

Gestione degli errori

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