Questa pagina descrive come scrivere un timestamp di commit per ogni operazione di inserimento e aggiornamento che esegui con Spanner nei database con dialetto PostgreSQL.
Inserisci i timestamp di commit
Il timestamp di commit, basato sulla tecnologia TrueTime, è l'ora in cui una transazione viene eseguita nel database. Puoi archiviare in modo atomico il timestamp di commit di una transazione in una colonna. Utilizzando i timestamp di commit archiviati nelle tabelle, puoi determinare l'ordine esatto delle mutazioni e creare funzionalità come i log delle modifiche.
Per inserire i timestamp dei commit nel database, completa i seguenti passaggi:
Crea una colonna di tipo
SPANNER.COMMIT_TIMESTAMP
. Ad esempio:CREATE TABLE Performances ( ... LastUpdateTime SPANNER.COMMIT_TIMESTAMP NOT NULL, ... PRIMARY KEY (...) ) ;
Se esegui inserimenti o aggiornamenti con DML, utilizza la funzione
SPANNER.PENDING_COMMIT_TIMESTAMP()
per scrivere il timestamp del commit.Se esegui inserimenti o aggiornamenti con istruzioni preparate o mutazioni, utilizza la stringa segnaposto
SPANNER.COMMIT_TIMESTAMP()
per la colonna del timestamp di commit. Puoi anche utilizzare la costante del timestamp del commit fornita dalla libreria client. Ad esempio, questa costante nel client Java èValue.COMMIT_TIMESTAMP
.
Quando Spanner esegue il commit della transazione utilizzando questi segnaposto come valori delle colonne, il timestamp di commit effettivo viene scritto nella colonna specificata. Puoi quindi utilizzare questo valore della colonna per creare una cronologia degli aggiornamenti della tabella.
Non è garantito che i valori del timestamp del commit siano univoci. Le transazioni che scrivono in insiemi di campi non sovrapposti potrebbero avere lo stesso timestamp. Le transazioni che scrivono in insiemi di campi sovrapposti hanno timestamp univoci.
I timestamp di commit di Spanner hanno una granularità di microsecondi
e vengono convertiti in nanosecondi quando vengono memorizzati nelle colonne SPANNER.COMMIT_TIMESTAMP
.
Chiavi e indici
Puoi utilizzare una colonna timestamp di commit come colonna della chiave primaria o come colonna non chiave. Le chiavi primarie possono essere definite come ASC
o DESC
.
ASC
(impostazione predefinita) - Le chiavi crescenti sono ideali per rispondere alle query a partire da un momento specifico.DESC
: i tasti in ordine decrescente mantengono le righe più recenti nella parte superiore della tabella. Forniscono un accesso rapido ai record più recenti.
Evita gli hotspot
L'utilizzo dei timestamp di commit nei seguenti scenari crea hotspot, che riducono le prestazioni dei dati:
Colonna del timestamp del commit come prima parte della chiave primaria di una tabella.
CREATE TABLE Users ( LastAccess SPANNER.COMMIT_TIMESTAMP NOT NULL, UserId bigint NOT NULL, ... PRIMARY KEY (LastAccess, UserId) ) ;
Colonna della chiave primaria del timestamp di commit come prima parte di un indice secondario.
CREATE INDEX UsersByLastAccess ON Users(LastAccess)
o
CREATE INDEX UsersByLastAccessAndName ON Users(LastAccess, FirstName)
Gli hotspot riducono le prestazioni dei dati, anche con velocità di scrittura basse. Non si verifica un sovraccarico delle prestazioni se i timestamp di commit sono abilitati per le colonne non chiave che non sono indicizzate.
Aggiungere una colonna con il timestamp del commit a una tabella esistente
Per aggiungere una colonna con il timestamp del commit a una tabella esistente, utilizza l'istruzione ALTER TABLE
. Ad esempio, per aggiungere una colonna LastUpdateTime
alla tabella Performances
, utilizza la seguente istruzione:
ALTER TABLE Performances ADD COLUMN LastUpdateTime SPANNER.COMMIT_TIMESTAMP;
Scrivere un timestamp di commit utilizzando un'istruzione DML
Utilizzi la funzione SPANNER.PENDING_COMMIT_TIMESTAMP()
per scrivere il timestamp del commit in un'istruzione DML. Spanner seleziona il timestamp di commit quando viene eseguito il commit della transazione.
La seguente istruzione DML aggiorna la colonna LastUpdateTime
nella
tabella Performances
con il timestamp di commit:
UPDATE Performances SET LastUpdateTime = SPANNER.PENDING_COMMIT_TIMESTAMP()
WHERE SingerId=1 AND VenueId=2 AND EventDate="2015-10-21"
Inserire una riga utilizzando una mutazione
Quando inserisci una riga, Spanner scrive il valore del timestamp di commit solo
se includi la colonna nell'elenco delle colonne e passi la
stringa segnaposto spanner.commit_timestamp()
(o la costante della libreria client)
come valore. Ad esempio:
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Se hai mutazioni sulle righe di più tabelle, devi specificare
spanner.commit_timestamp()
(o la costante della libreria client) per la colonna
del timestamp di commit in ogni tabella.
Aggiorna una riga utilizzando una mutazione
Quando aggiorni una riga, Spanner scrive il valore del timestamp di commit solo
se includi la colonna nell'elenco delle colonne e passi la
stringa segnaposto spanner.commit_timestamp()
(o la costante della libreria client)
come valore. Non puoi aggiornare la chiave primaria di una riga. Per aggiornare
la chiave primaria, elimina la riga esistente e creane una nuova.
Ad esempio, per aggiornare una colonna del timestamp del commit denominata LastUpdateTime
:
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Se hai mutazioni su righe in più tabelle, devi specificare
spanner.commit_timestamp()
(o la costante
della libreria client) per la colonna del timestamp di commit in ogni tabella.
Eseguire query su una colonna del timestamp di commit
L'esempio seguente esegue una query sulla colonna del timestamp del commit della tabella.
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Fornisci il tuo valore per la colonna del timestamp del commit
Nel codice, puoi fornire un valore personalizzato per la colonna del timestamp del commit
anziché passare spanner.commit_timestamp()
(o la costante della libreria client disponibile)
come valore della colonna. Il valore deve essere un timestamp nel passato. Questa
limitazione garantisce che la scrittura dei timestamp sia un'operazione
economica e veloce. Un modo per verificare che un valore sia nel passato è confrontarlo con
il valore restituito dalla funzione SQL CURRENT_TIMESTAMP
. Il server restituisce un errore
FailedPrecondition
se viene specificato un timestamp futuro.
Creare un log delle modifiche
Supponiamo di voler creare un log delle modifiche di ogni mutazione che si verifica in una tabella e poi utilizzare questo log per l'audit. Un esempio è una tabella che memorizza la cronologia delle modifiche apportate ai documenti di elaborazione di testi. Il timestamp del commit semplifica la creazione del log delle modifiche, perché i timestamp possono imporre l'ordinamento delle voci del log delle modifiche. Puoi creare un changelog che memorizzi la cronologia delle modifiche apportate a un determinato documento utilizzando uno schema come il seguente esempio:
CREATE TABLE Documents (
UserId int8 NOT NULL,
DocumentId int8 NOT NULL,
Contents text NOT NULL,
PRIMARY KEY (UserId, DocumentId)
);
CREATE TABLE DocumentHistory (
UserId int8 NOT NULL,
DocumentId int8 NOT NULL,
Ts SPANNER.COMMIT_TIMESTAMP NOT NULL,
Delta text,
PRIMARY KEY (UserId, DocumentId, Ts)
) INTERLEAVE IN PARENT Documents;
Per creare un log delle modifiche, inserisci una nuova riga in DocumentHistory
nella stessa
transazione in cui inserisci o aggiorni una riga in Document
. Nell'inserimento
della nuova riga in DocumentHistory
, utilizza il segnaposto
spanner.commit_timestamp()
(o la costante della libreria client) per indicare
a Spanner di scrivere il timestamp del commit nella colonna Ts
.
L'interleaving della tabella DocumentsHistory
con la tabella Documents
consente
la località dei dati e inserimenti e aggiornamenti più efficienti. Tuttavia, aggiunge anche il
vincolo che le righe padre e figlio devono essere eliminate insieme. Per conservare le
righe in DocumentHistory
dopo l'eliminazione delle righe in Documents
, non
alternare le tabelle.
Ottimizzare le query sui dati recenti con i timestamp di commit
I timestamp di commit ottimizzano il database Spanner e possono ridurre l'I/O delle query durante il recupero dei dati scritti dopo un determinato periodo di tempo.
Per attivare questa ottimizzazione, la clausola WHERE
di una query deve includere un
confronto tra la colonna del timestamp di commit di una tabella e un orario specifico
che fornisci, con i seguenti attributi:
Fornisci l'ora specifica come espressione costante: un valore letterale, un parametro o una funzione i cui argomenti vengono valutati come costanti.
Confronta se il timestamp di commit è più recente dell'ora specificata, tramite gli operatori
>
o>=
.Se vuoi, aggiungi ulteriori limitazioni alla clausola
WHERE
conAND
. L'estensione della clausola conOR
squalifica la query da questa ottimizzazione.
Ad esempio, considera la seguente tabella Performances
, che include
una colonna con il timestamp del commit:
CREATE TABLE Performances (
SingerId bigint NOT NULL,
VenueId bigint NOT NULL,
EventDate timestamp with time zone NOT NULL,
Revenue bigint,
LastUpdateTime spanner.commit_timestamp,
PRIMARY KEY(SingerId, VenueId, EventDate)
);
Questa query beneficia dell'ottimizzazione del timestamp di commit descritta in precedenza, perché ha un confronto maggiore o uguale tra la colonna del timestamp di commit della tabella e un'espressione costante, in questo caso, un valore letterale:
SELECT * FROM Performances WHERE LastUpdateTime >= '2022-01-01';