Spanner ti consente di aggiornare lo schema senza tempi di inattività. Puoi aggiornare lo schema di un database esistente in diversi modi:
Nella console Google Cloud
Invia un comando
ALTER TABLE
nella pagina Spanner Studio.Per accedere alla pagina Spanner Studio, fai clic su Spanner Studio nella pagina Panoramica del database o Panoramica della tabella.
Utilizzo dello strumento a riga di comando
gcloud spanner
Invia un comando
ALTER TABLE
utilizzando il comando gcloud spanner database ddl update.Utilizzare le librerie client
Utilizzare l'API REST di
projects.instances.databases.updateDdl
Utilizzo dell'API RPC
UpdateDatabaseDdl
Aggiornamenti dello schema supportati
Spanner supporta i seguenti aggiornamenti dello schema di un database esistente:
- Crea una nuova tabella. Le colonne nelle nuove tabelle possono essere
NOT NULL
. - Elimina una tabella se al suo interno non sono presenti altre tabelle con interleaving e se non ha indici secondari.
- Crea o elimina una tabella con una chiave esterna.
- Aggiungi o rimuovi una chiave esterna da una tabella esistente.
- Aggiungi una colonna non chiave a qualsiasi tabella. Le nuove colonne non chiave non possono essere
NOT NULL
. - Elimina una colonna non chiave da qualsiasi tabella, a meno che non sia utilizzata da un indice secondario, una chiave esterna, una colonna generata archiviata o un vincolo di controllo.
- Aggiungi
NOT NULL
a una colonna non chiave, escluseARRAY
colonne. - Rimuovi
NOT NULL
da una colonna non chiave. - Modifica una colonna
STRING
in una colonnaBYTES
o una colonnaBYTES
in una colonnaSTRING
. - Aumenta o riduci il limite di lunghezza per un tipo
STRING
oBYTES
(inclusoMAX
), a meno che non si tratti di una colonna di chiave primaria ereditata da una o più tabelle figlio. - Abilita o disabilita i timestamp del commit nelle colonne del valore e della chiave primaria.
- Aggiungi o rimuovi un indice secondario.
- Aggiungi o rimuovi un vincolo di controllo da una tabella esistente.
- Aggiungi o rimuovi una colonna generata archiviata da una tabella esistente.
- Crea un nuovo pacchetto di statistiche di ottimizzazione.
Prestazioni di aggiornamento dello schema
Gli aggiornamenti dello schema in Spanner non richiedono tempi di inattività. Quando invii un batch di istruzioni DDL a un database Spanner, puoi continuare a eseguire operazioni di lettura e scrittura sul database senza interruzioni mentre Spanner applica l'aggiornamento come operazione a lunga esecuzione.
Il tempo necessario per eseguire un'istruzione DDL dipende dalla necessità o meno di convalidare i dati esistenti o di eseguire il backfill di dati durante l'aggiornamento. Ad esempio,
se aggiungi l'annotazione NOT NULL
a una colonna esistente, Spanner deve
leggere tutti i valori nella colonna per assicurarsi che la colonna non contenga
valori NULL
. Questo passaggio può richiedere molto tempo se sono presenti molti dati da convalidare. Un altro esempio è l'aggiunta di un indice a un database: Spanner esegue il backfill dell'indice utilizzando i dati esistenti e questo processo può richiedere molto tempo, a seconda di come la definizione dell'indice e le dimensioni della tabella di base corrispondente. Tuttavia, se aggiungi una nuova colonna a una tabella, non ci sono dati esistenti da convalidare, quindi Spanner può eseguire l'aggiornamento più rapidamente.
Per riassumere, gli aggiornamenti dello schema che non richiedono Spanner per convalidare i dati esistenti possono essere eseguiti in pochi minuti. Gli aggiornamenti dello schema che richiedono la convalida possono richiedere più tempo, a seconda della quantità di dati esistenti da convalidare, ma la convalida dei dati avviene in background con una priorità inferiore rispetto al traffico di produzione. Gli aggiornamenti dello schema che richiedono la convalida dei dati sono descritti più dettagliatamente nella prossima sezione.
Aggiornamenti dello schema convalidati in base alle definizioni delle viste
Quando esegui un aggiornamento dello schema, Spanner verifica che l'aggiornamento non invaliderà le query utilizzate per definire le viste esistenti. Se la convalida ha esito positivo, l'aggiornamento dello schema ha esito positivo. Se la convalida non ha esito positivo, l'aggiornamento dello schema non va a buon fine. Per ulteriori dettagli, consulta Best practice per la creazione di viste.
Aggiornamenti dello schema che richiedono la convalida dei dati
Puoi eseguire aggiornamenti dello schema che richiedono la verifica che i dati esistenti soddisfino i nuovi vincoli. Quando un aggiornamento dello schema richiede la convalida dei dati, Spanner non consente gli aggiornamenti dello schema in conflitto per le entità dello schema interessate e convalida i dati in background. Se la convalida ha esito positivo, l'aggiornamento dello schema ha esito positivo. Se la convalida non ha esito positivo, l'aggiornamento dello schema non va a buon fine. Le operazioni di convalida vengono eseguite come operazioni a lunga esecuzione. Puoi controllare lo stato di queste operazioni per determinare se sono riuscite o non riuscite.
Ad esempio, supponi di aver definito una tabella Songwriters
nel tuo schema:
GoogleSQL
CREATE TABLE Songwriters (
Id INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
Nickname STRING(MAX),
OpaqueData BYTES(MAX),
) PRIMARY KEY (Id);
I seguenti aggiornamenti dello schema sono consentiti, ma richiedono una convalida e il loro completamento potrebbe richiedere più tempo, a seconda della quantità di dati esistenti:
Aggiunta dell'annotazione
NOT NULL
a una colonna non chiave. Ad esempio:ALTER TABLE Songwriters ALTER COLUMN Nickname STRING(MAX) NOT NULL;
Ridurre la lunghezza di una colonna. Ad esempio:
ALTER TABLE Songwriters ALTER COLUMN FirstName STRING(10);
Modifica da
BYTES
aSTRING
. Ad esempio:ALTER TABLE Songwriters ALTER COLUMN OpaqueData STRING(MAX);
Abilitazione dei timestamp del commit su una colonna
TIMESTAMP
esistente. Ad esempio:ALTER TABLE Albums ALTER COLUMN LastUpdateTime SET OPTIONS (allow_commit_timestamp = true);
Aggiunta di un vincolo di controllo a una tabella esistente.
Aggiunta di una colonna generata archiviata a una tabella esistente.
Creazione di una nuova tabella con una chiave esterna.
Aggiunta di una chiave esterna a una tabella esistente.
Questi aggiornamenti dello schema non riescono se i dati sottostanti non soddisfano i nuovi vincoli. Ad esempio, l'istruzione ALTER TABLE Songwriters ALTER COLUMN Nickname
STRING(MAX) NOT NULL
riportata sopra non riesce se un valore nella colonna Nickname
è NULL
, perché i dati esistenti non soddisfano il vincolo NOT NULL
della nuova definizione.
La convalida dei dati può richiedere da diversi minuti a molte ore. Il tempo per completare la convalida dei dati dipende da:
- La dimensione del set di dati
- La capacità di calcolo dell'istanza
- Il carico sull'istanza
Alcuni aggiornamenti dello schema possono modificare il comportamento delle richieste al database prima del completamento dell'aggiornamento dello schema. Ad esempio, se aggiungi NOT NULL
a una
colonna, Spanner inizia quasi immediatamente a rifiutare le scritture per le nuove richieste che utilizzano NULL
per la colonna. Se il nuovo aggiornamento dello schema non va a buon fine per la convalida dei dati, ci sarà un certo periodo di tempo in cui le scritture sono state bloccate, anche se sarebbero state accettate dal precedente schema.
Puoi annullare un'operazione di convalida dei dati a lunga esecuzione utilizzando il metodo projects.instances.databases.operations.cancel
o gcloud spanner operations
.
Ordine di esecuzione delle istruzioni in batch
Se utilizzi Google Cloud CLI, l'API REST o l'API RPC, puoi emettere un batch di una o più istruzioni CREATE
, ALTER
o DROP
.
Spanner applica le istruzioni dello stesso batch in ordine, arrestandosi al primo errore. Se l'applicazione di un'istruzione genera un errore, l'istruzione viene restituita indietro. Il rollback dei risultati di eventuali istruzioni applicate in precedenza nel batch non viene eseguito.
Spanner può combinare e riordinare le istruzioni di diversi batch, mescolando potenzialmente istruzioni di batch diversi in un'unica modifica atomica applicata al database. All'interno di ogni modifica atomica, le istruzioni
di diversi batch avvengono in ordine arbitrario. Ad esempio, se un batch di istruzioni contiene ALTER TABLE MyTable ALTER COLUMN MyColumn STRING(50)
e un altro batch di istruzioni contiene ALTER TABLE MyTable ALTER COLUMN MyColumn
STRING(20)
, Spanner lascerà la colonna in uno di questi due stati, senza specificare quale.
Versioni dello schema create durante gli aggiornamenti dello schema
Spanner utilizza il controllo delle versioni dello schema in modo che non ci siano tempi di inattività durante l'aggiornamento dello schema a un database di grandi dimensioni. Spanner mantiene la versione precedente dello schema per supportare le letture durante l'elaborazione dell'aggiornamento dello schema. Spanner crea quindi una o più nuove versioni dello schema per elaborare l'aggiornamento dello schema. Ogni versione contiene il risultato di una raccolta di istruzioni in una singola modifica atomica, come descritto sopra.
Le versioni dello schema non corrispondono necessariamente a gruppi di istruzioni DDL o singole istruzioni DDL. Alcune singole istruzioni DDL, come la creazione di indici per tabelle di base esistenti o istruzioni che richiedono la convalida dei dati, generano più versioni dello schema. In altri casi, è possibile raggruppare diverse istruzioni DDL in un'unica versione. Le versioni precedenti dello schema possono consumare significative risorse di server e di archiviazione e vengono conservate fino alla scadenza (non sono più necessarie per le letture di versioni precedenti dei dati).
La tabella seguente mostra il tempo necessario a Spanner per aggiornare uno schema.
Operazione schema | Durata stimata |
---|---|
CREATE TABLE |
Minuti |
CREATE INDEX |
Da minuti a ore, se la tabella di base viene creata prima dell'indice. Minuti, se l'istruzione viene eseguita contemporaneamente all'istruzione |
DROP TABLE |
Minuti |
DROP INDEX |
Minuti |
ALTER TABLE ... ADD COLUMN |
Minuti |
ALTER TABLE ... ALTER COLUMN |
Da minuti a ore, se è richiesta la convalida in background. Minuti, se la convalida in background non è richiesta. |
ALTER TABLE ... DROP COLUMN |
Minuti |
ANALYZE |
Da minuti a ore, a seconda delle dimensioni del database. |
Modifiche ai tipi di dati e modifiche in tempo reale
Se modifichi il tipo di dati di una colonna monitorata da un flusso di modifiche, il campo column_types
dei record di modifiche in tempo reale pertinenti successivi rifletterà il nuovo tipo, così come i dati JSON old_values
all'interno del campo mods
dei record.
new_values
del campo mods
di un record di modifiche in tempo reale corrisponde sempre al tipo corrente di una colonna. La modifica del tipo di dati di una colonna monitorata non
influisce sui record di modifiche in tempo reale che precedono tale modifica.
Nel caso specifico di una modifica da BYTES
a STRING
, Spanner convalida i valori precedenti della colonna nell'ambito dell'aggiornamento dello schema.
Di conseguenza, Spanner ha decodificato in modo sicuro i vecchi valori di tipo BYTES
in stringhe quando scrive tutti i record di flussi di modifiche successivi.
Best practice per gli aggiornamenti dello schema
Le seguenti sezioni descrivono le best practice per l'aggiornamento degli schemi.
Procedure prima di eseguire l'aggiornamento dello schema
Prima di eseguire un aggiornamento dello schema:
Verifica che tutti i dati esistenti nel database che stai modificando soddisfino i vincoli imposti dall'aggiornamento dello schema. Poiché l'esito positivo di alcuni tipi di aggiornamenti dello schema dipende dai dati nel database e non solo dal suo schema attuale, un aggiornamento riuscito di un database di test non garantisce che l'aggiornamento di un database di produzione sia riuscito. Ecco alcuni esempi comuni:
- Se aggiungi un'annotazione
NOT NULL
a una colonna esistente, verifica che la colonna non contenga valoriNULL
esistenti. - Se stai accorciando la lunghezza consentita di una colonna
STRING
oBYTES
, verifica che tutti i valori esistenti in quella colonna soddisfino il vincolo di lunghezza desiderato.
- Se aggiungi un'annotazione
Se stai scrivendo in una colonna, in una tabella o in un indice in fase di aggiornamento dello schema, assicurati che i valori che scrivi soddisfino i nuovi vincoli.
Se stai eliminando una colonna, una tabella o un indice, assicurati di non continuare a eseguire operazioni di lettura o scrittura su questo elemento.
Limitare la frequenza degli aggiornamenti dello schema
Se esegui troppi aggiornamenti dello schema in un breve periodo di tempo, Spanner potrebbe throttle
l'elaborazione degli aggiornamenti dello schema in coda. perché Spanner limita la quantità di spazio
per l'archiviazione delle versioni dello schema. L'aggiornamento dello schema potrebbe essere limitato se sono presenti troppe versioni precedenti dello schema durante il periodo di conservazione. La frequenza massima delle modifiche allo schema dipende da molti fattori, uno dei quali è il numero totale di colonne nel database. Ad esempio, un database con 2000 colonne (circa 2000 righe in INFORMATION_SCHEMA.COLUMNS
) è in grado di eseguire al massimo 1500 modifiche semplici allo schema (meno se la modifica allo schema richiede più versioni) entro il periodo di conservazione. Per visualizzare lo stato degli aggiornamenti in corso dello schema, utilizza il comando gcloud spanner operations list
e filtra per operazioni di tipo DATABASE_UPDATE_DDL
. Per annullare un aggiornamento dello schema in corso, utilizza il comando gcloud spanner operations cancel
e specifica l'ID operazione.
Il modo in cui le istruzioni DDL vengono raggruppate e il relativo ordine all'interno di ogni batch può influire sul numero di versioni dello schema risultanti. Per massimizzare il numero di aggiornamenti dello schema che puoi eseguire in un determinato periodo di tempo, devi utilizzare il batch che riduca al minimo il numero di versioni dello schema. Alcune regole generali sono descritte negli aggiornamenti di grandi dimensioni.
Come descritto nelle versioni schema, alcune istruzioni DDL creano più versioni di schema, importanti per la valutazione in batch e in ordine all'interno di ogni batch. Esistono due tipi principali di istruzioni che possono creare più versioni dello schema:
- Istruzioni che potrebbero dover eseguire il backfill dei dati dell'indice, come
CREATE INDEX
- Istruzioni che potrebbero dover convalidare i dati esistenti, come l'aggiunta di
NOT NULL
Tuttavia, questi tipi di istruzioni non creano sempre più versioni dello schema. Spanner cercherà di rilevare quando questi tipi di istruzioni possono essere ottimizzati per evitare di utilizzare più versioni dello schema, il che dipende dal batch.
Ad esempio, un'istruzione CREATE INDEX
che si verifica nello stesso batch di un'istruzione CREATE TABLE
per la tabella di base dell'indice, senza istruzioni intermedie per altre tabelle, può evitare di dover eseguire il backfill dei dati dell'indice, poiché Spanner può garantire che la tabella di base sia vuota al momento della creazione dell'indice. La sezione Aggiornamenti di grandi dimensioni descrive come
utilizzare questa proprietà per creare molti indici in modo efficiente.
Se non riesci a raggruppare le istruzioni DDL per evitare di creare molte versioni dello schema, devi limitare il numero di aggiornamenti dello schema allo schema di un singolo database entro il relativo periodo di conservazione. Aumenta la finestra temporale durante gli aggiornamenti dello schema per consentire a Spanner di rimuovere le versioni precedenti dello schema prima che ne vengano create di nuove.
- Per alcuni sistemi di gestione dei database relazionali, esistono pacchetti software che eseguono una lunga serie di aggiornamenti dello schema di upgrade e downgrade al database per ogni deployment di produzione. Questi tipi di processi non sono consigliati per Spanner.
- Spanner è ottimizzato per utilizzare le chiavi primarie per partizionare i dati per soluzioni multitenancy. Le soluzioni multitenancy che utilizzano tabelle separate per ogni cliente possono comportare un enorme backlog di operazioni di aggiornamento dello schema il cui completamento richiede molto tempo.
- Gli aggiornamenti dello schema che richiedono la convalida o il backfill dell'indice utilizzano più risorse del server, perché ogni istruzione crea internamente più versioni dello schema.
Opzioni per gli aggiornamenti dello schema di grandi dimensioni
Il modo migliore per creare una tabella e un numero elevato di indici in quella tabella è crearli tutti contemporaneamente, in modo che venga creata una sola versione dello schema. La best practice prevede di creare gli indici subito dopo la tabella nell'elenco delle istruzioni DDL. Puoi creare la tabella e i suoi indici quando crei il database o in un singolo batch di grandi dimensioni di istruzioni. Se devi creare molte tabelle, ognuna con molti indici, puoi includere tutte le istruzioni in un singolo batch. Puoi includere diverse migliaia di istruzioni in un singolo batch quando tutte le istruzioni possono essere eseguite insieme utilizzando un'unica versione di schema.
Quando un'istruzione richiede il backfill dei dati dell'indice o l'esecuzione della convalida dei dati, non può essere eseguita in una singola versione dello schema. Questo accade per le istruzioni CREATE INDEX
quando la tabella di base dell'indice esiste già (perché è stata creata in un batch precedente di istruzioni DDL o perché era presente un'istruzione nel batch tra le istruzioni CREATE TABLE
e CREATE INDEX
che richiedeva più versioni dello schema). Spanner richiede che non ci siano
più di 10 istruzioni di questo tipo in un singolo batch. La creazione di indici che richiede il backfill, in particolare utilizza diverse versioni dello schema per indice, perciò è buona norma creare non più di tre nuovi indici che richiedono il backfill al giorno (indipendentemente dalle modalità di raggruppamento, a meno che tale operazione in batch non possa evitare il backfill).
Ad esempio, questo gruppo di istruzioni utilizzerà un'unica versione dello schema:
GoogleSQL
CREATE TABLE Singers ( SingerId INT64 NOT NULL, FirstName STRING(1024), LastName STRING(1024), ) PRIMARY KEY (SingerId); CREATE INDEX SingersByFirstName ON Singers(FirstName); CREATE INDEX SingersByLastName ON Singers(LastName); CREATE TABLE Albums ( SingerId INT64 NOT NULL, AlbumId INT64 NOT NULL, AlbumTitle STRING(MAX), ) PRIMARY KEY (SingerId, AlbumId); CREATE INDEX AlbumsByTitle ON Albums(AlbumTitle);
Al contrario, questo batch utilizzerà molte versioni dello schema, perché UnrelatedIndex
richiede il backfill (poiché la sua tabella di base deve essere già esistente) e questo obbliga
a richiedere anche il backfill per tutti i seguenti indici (anche se
si trovano nello stesso batch delle tabelle di base):
GoogleSQL
CREATE TABLE Singers ( SingerId INT64 NOT NULL, FirstName STRING(1024), LastName STRING(1024), ) PRIMARY KEY (SingerId); CREATE TABLE Albums ( SingerId INT64 NOT NULL, AlbumId INT64 NOT NULL, AlbumTitle STRING(MAX), ) PRIMARY KEY (SingerId, AlbumId); CREATE INDEX UnrelatedIndex ON UnrelatedTable(UnrelatedIndexKey); CREATE INDEX SingersByFirstName ON Singers(FirstName); CREATE INDEX SingersByLastName ON Singers(LastName); CREATE INDEX AlbumsByTitle ON Albums(AlbumTitle);
È preferibile spostare la creazione di UnrelatedIndex
alla fine del batch o in un batch diverso per ridurre al minimo le versioni dello schema.
Attendi il completamento delle richieste API
Quando effettui richieste projects.instances.databases.updateDdl
(API REST) o UpdateDatabaseDdl
(API RPC), utilizza rispettivamente projects.instances.databases.operations.get
(API REST) o GetOperation
(API RPC), in modo da attendere il completamento di ogni richiesta prima di avviarne una nuova. Il completamento di ogni richiesta consente all'applicazione di monitorare l'avanzamento degli aggiornamenti dello schema. Inoltre, mantiene il backlog degli aggiornamenti dello schema in attesa a una dimensione gestibile.
Caricamento collettivo
Se esegui il caricamento in blocco dei dati nelle tabelle dopo la creazione, in genere è più efficiente creare gli indici dopo aver caricato i dati. Se aggiungi diversi indici, potrebbe essere più efficiente creare il database con tutte le tabelle e gli indici nello schema iniziale, come descritto nelle opzioni per aggiornamenti di grandi dimensioni.