Spanner fornisce statistiche di blocco che consentono di identificare la chiave di riga e le colonne delle tabelle che sono state le fonti principali dei conflitti di blocco delle transazioni nel database durante un determinato periodo di tempo. Puoi recuperare queste statistiche dalle tabelle di sistema SPANNER_SYS.LOCK_STATS*
utilizzando le istruzioni SQL.
Disponibilità
I dati di SPANNER_SYS
sono disponibili solo tramite le interfacce SQL, ad esempio:
Pagina Spanner Studio di un database nella console Google Cloud
Il comando
gcloud spanner databases execute-sql
La dashboard Blocca insight
L'API
executeQuery
Altri metodi di lettura singola forniti da Spanner non supportano SPANNER_SYS
.
Blocca le statistiche per chiave di riga
Le seguenti tabelle monitorano la chiave di riga con il tempo di attesa più elevato:
SPANNER_SYS.LOCK_STATS_TOP_MINUTE
: chiavi di riga con i tempi di attesa per il blocco più elevati a intervalli di 1 minuto.SPANNER_SYS.LOCK_STATS_TOP_10MINUTE
: chiavi di riga con i tempi di attesa per il blocco più elevati a intervalli di 10 minuti.SPANNER_SYS.LOCK_STATS_TOP_HOUR
: chiavi di riga con i tempi di attesa per il blocco più elevati a intervalli di 1 ora
Queste tabelle hanno le seguenti proprietà:
Ogni tabella contiene dati per intervalli di tempo non sovrapposti della lunghezza specificata dal nome della tabella.
Gli intervalli si basano sugli orari di orologio. Gli intervalli di 1 minuto terminano al minuto, gli intervalli di 10 minuti terminano ogni 10 minuti a partire da un'ora e gli intervalli di 1 ora terminano al giorno. Dopo ogni intervallo, Spanner raccoglie i dati da tutti i server e subito dopo rende i dati disponibili nelle tabelle SPANNER_SYS.
Ad esempio, alle 11:59:30, gli intervalli più recenti disponibili per le query SQL sono:
- 1 minuto: 11:58:00-11:58:59
- 10 minuti: 11:40:00-11:49:59
- 1 ora: 10:00:00-10:59:59
Spanner raggruppa le statistiche in base all'intervallo di chiavi di chiave di riga iniziale.
Ogni riga contiene le statistiche relative al tempo di attesa totale per il blocco di un particolare intervallo di chiave di riga iniziale per il quale Spanner acquisisce le statistiche durante l'intervallo specificato.
Se Spanner non è in grado di archiviare informazioni su ogni intervallo di chiave di riga per il tempo di attesa del blocco durante l'intervallo, il sistema dà la priorità all'intervallo di chiave di riga con il tempo di attesa per il blocco più elevato durante l'intervallo specificato.
Schema tabella
Nome colonna | Tipo | Descrizione |
---|---|---|
INTERVAL_END |
TIMESTAMP |
Fine dell'intervallo di tempo in cui si sono verificati i conflitti di blocco inclusi. |
ROW_RANGE_START_KEY |
BYTES(MAX) |
La chiave di riga in cui si è verificato il conflitto di blocco. Quando il conflitto riguarda un intervallo di righe, questo valore rappresenta la chiave iniziale dell'intervallo. Un segno più, + , indica un intervallo.
Per maggiori informazioni, consulta Che cos'è una chiave iniziale dell'intervallo di righe.
|
LOCK_WAIT_SECONDS |
FLOAT64 |
Il tempo di attesa cumulativo per il blocco dei conflitti di blocco registrato per tutte le colonne nell'intervallo di chiave di riga, in secondi. |
SAMPLE_LOCK_REQUESTS |
ARRAY<STRUCT<
|
Ogni voce in questo array corrisponde a una richiesta di blocco di esempio che ha contribuito al conflitto di blocco in attesa di un blocco o di impedire ad altre transazioni di eseguire il blocco sulla chiave di riga specificata (intervallo). Il numero massimo di campioni in questo array è 20.
Ogni esempio contiene i seguenti tre campi:
|
Modalità di blocco
Le operazioni di Spanner acquisiscono i blocchi quando fanno parte di una transazione di lettura e scrittura. Le transazioni di sola lettura non acquisiscono blocchi. Spanner utilizza diverse modalità di blocco per massimizzare il numero di transazioni che hanno accesso a una determinata cella di dati in un determinato momento. Ogni blocco ha caratteristiche diverse. Ad esempio, alcuni blocchi possono essere condivisi tra più transazioni, mentre altri no.
Può verificarsi un conflitto di blocco quando tenti di acquisire una delle seguenti modalità di blocco in una transazione.
ReaderShared
Blocco: un blocco che consente ad altre letture di accedere ai dati finché la transazione non è pronta per il commit. Questo blocco condiviso viene acquisito quando una transazione di lettura-scrittura legge i dati.Blocco
WriterShared
: questo blocco viene acquisito quando una transazione di lettura-scrittura prova a eseguire il commit di una scrittura.Exclusive
Blocco: viene acquisito un blocco esclusivo quando una transazione di lettura-scrittura, che ha già acquisito un blocco ReaderShared, tenta di scrivere dati al termine della lettura. Un blocco esclusivo è un upgrade di un bloccoReaderShared
. Un blocco esclusivo è un caso speciale di una transazione in cui vengono bloccati contemporaneamente sia il bloccoReaderShared
sia il bloccoWriterShared
. Nessun'altra transazione può acquisire alcun blocco sulla stessa cella.WriterSharedTimestamp
Blocco: un tipo speciale di bloccoWriterShared
che viene acquisito quando vengono inserite nuove righe in una tabella con un timestamp del commit come parte della chiave primaria. Questo tipo di blocco impedisce ai partecipanti alla transazione di creare la stessa riga e, di conseguenza, di creare conflitti tra loro. Spanner aggiorna la chiave della riga inserita in modo che corrisponda al timestamp di commit della transazione che ha eseguito l'inserimento.
Per ulteriori informazioni sui tipi di transazioni e sui tipi di blocchi disponibili, consulta Transazioni.
Conflitti modalità di blocco
La tabella seguente mostra i possibili conflitti tra le diverse modalità di blocco.
Modalità di blocco | ReaderShared |
WriterShared |
Exclusive |
WriterSharedTimestamp |
---|---|---|---|---|
ReaderShared |
No | Sì | Sì | Sì |
WriterShared |
Sì | No | Sì | Non applicabile |
Exclusive |
Sì | Sì | Sì | Non applicabile |
WriterSharedTimestamp |
Sì | Non applicabile | Non applicabile | Sì |
I blocchi WriterSharedTimestamp
vengono utilizzati solo quando vengono inserite nuove righe con un
timestamp come parte della chiave primaria. I blocchi WriterShared
e Exclusive
vengono
utilizzati per la scrittura nelle celle esistenti o per l'inserimento di nuove righe senza timestamp. Di conseguenza, WriterSharedTimestamp
non può entrare in conflitto con altri tipi di blocchi e questi scenari sono indicati come Non applicabile nella tabella precedente.
L'unica eccezione è ReaderShared
, che può essere applicata a righe non esistenti
e, pertanto, potrebbe essere in conflitto con WriterSharedTimestamp
. Ad
esempio, una scansione completa della tabella blocca l'intera tabella anche per le righe che non sono state
create, quindi è possibile che ReaderShared
entri in conflitto con
WriterSharedTimestamp
.
Che cos'è una chiave iniziale dell'intervallo di righe?
La colonna ROW_RANGE_START_KEY
identifica la chiave primaria composita, o
la chiave primaria iniziale di un intervallo di righe, che presenta conflitti di blocco. Lo schema
seguente viene utilizzato per illustrare un esempio.
CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
SingerInfo BYTES(MAX),
) PRIMARY KEY (SingerId);
CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE;
CREATE TABLE Songs (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
TrackId INT64 NOT NULL,
SongName STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId, TrackId),
INTERLEAVE IN PARENT Albums ON DELETE CASCADE;
CREATE TABLE Users (
UserId INT64 NOT NULL,
LastAccess TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
...
) PRIMARY KEY (UserId, LastAccess);
Come mostra la seguente tabella di intervalli di chiavi di riga e di riga, un intervallo è rappresentato da un segno più ("+") nella chiave. In questi casi, la chiave rappresenta la chiave iniziale di un intervallo di chiavi in cui si è verificato un conflitto di blocco.
ROW_RANGE_START_KEY | Spiegazione |
---|---|
cantanti(2) | Tavolo dei cantanti presso SingerId=2 |
album(2;1) | Tabella album nella chiave SingerId=2,AlbumId=1 |
canzoni(2,1,5) | Tabella brani nella chiave SingerId=2,AlbumId=1,TrackId=5 |
brani(2,1,5+) | Intervallo di chiavi della tabella Brani che inizia con SingerId=2,AlbumId=1,TrackId=5 |
album(2,1+) | Intervallo di chiavi della tabella Album che inizia con SingerId=2,AlbumId=1 |
utenti(3, 2020-11-01 12:34:56.426426+00:00) | Tabella degli utenti nella chiave UserId=3, LastAccess=commit_timestamp |
Statistiche aggregate
SPANNER_SYS
contiene anche tabelle per archiviare dati aggregati per le statistiche di blocco acquisite da Spanner in un periodo di tempo specifico:
SPANNER_SYS.LOCK_STATS_TOTAL_MINUTE
: statistiche aggregate per tutti i blocchi in attesa a intervalli di 1 minuto.SPANNER_SYS.LOCK_STATS_TOTAL_10MINUTE
: statistiche aggregate per tutti i blocchi in attesa a intervalli di 10 minuti.SPANNER_SYS.LOCK_STATS_TOTAL_HOUR
: statistiche aggregate per tutte le attese di blocco a intervalli di 1 ora.
Le tabelle delle statistiche aggregate hanno le seguenti proprietà:
Ogni tabella contiene dati per intervalli di tempo non sovrapposti della lunghezza specificata dal nome della tabella.
Gli intervalli si basano sugli orari di orologio. Gli intervalli di 1 minuto terminano al minuto, gli intervalli di 10 minuti terminano ogni 10 minuti a partire da un'ora e gli intervalli di 1 ora terminano al giorno.
Ad esempio, alle 11:59:30, gli intervalli più recenti disponibili per le query SQL sulle statistiche di blocco aggregate sono:
- 1 minuto: 11:58:00-11:58:59
- 10 minuti: 11:40:00-11:49:59
- 1 ora: 10:00:00-10:59:59
Ogni riga contiene le statistiche per tutte le attese del blocco sul database durante l'intervallo specificato, aggregate insieme. C'è una sola riga per ogni intervallo di tempo.
Le statistiche acquisite nelle tabelle
SPANNER_SYS.LOCK_STATS_TOTAL_*
includono le attese di blocco che Spanner non ha acquisito nelle tabelleSPANNER_SYS.LOCK_STATS_TOP_*
.Alcune colonne di queste tabelle sono esposte come metriche in Cloud Monitoring. Le metriche esposte sono:
- Tempo di attesa per il blocco
Per maggiori informazioni, consulta la sezione Metriche di Spanner.
Schema tabella
Nome colonna | Tipo | Descrizione |
---|---|---|
INTERVAL_END |
TIMESTAMP |
Fine dell'intervallo di tempo in cui si è verificato il conflitto di blocco. |
TOTAL_LOCK_WAIT_SECONDS |
FLOAT64 |
Tempo totale di attesa per il blocco per i conflitti di blocco registrati per l'intero database, in secondi. |
Esempi di query
Di seguito è riportato un esempio di istruzione SQL che puoi utilizzare per recuperare le statistiche di blocco. Puoi eseguire queste istruzioni SQL utilizzando le librerie client, gcloud spanner o la console Google Cloud.
Elenca le statistiche di blocco per l'intervallo di 1 minuto precedente
La seguente query restituisce le informazioni sull'attesa per il blocco per ogni chiave di riga con un conflitto di blocco, inclusa la frazione dei conflitti di blocco totali, durante l'intervallo di tempo di 1 minuto più recente.
La funzione CAST()
converte il campo row_range_start_key BYTES in un STRING.
SELECT CAST(s.row_range_start_key AS STRING) AS row_range_start_key,
t.total_lock_wait_seconds,
s.lock_wait_seconds,
s.lock_wait_seconds/t.total_lock_wait_seconds frac_of_total,
s.sample_lock_requests
FROM spanner_sys.lock_stats_total_minute t, spanner_sys.lock_stats_top_minute s
WHERE t.interval_end =
(SELECT MAX(interval_end)
FROM spanner_sys.lock_stats_total_minute)
AND s.interval_end = t.interval_end
ORDER BY s.lock_wait_seconds DESC;
Output query
row_range_start_key | total_lock_wait_seconds | lock_wait_seconds | frac_of_total | sample_lock_requests |
---|---|---|---|---|
Brani(2,1,1) | 2,37 | 1,76 | 0,7426 | LOCK_MODE: ReaderShared COLONNA: Informazioni su Singers.Singer LOCK_MODE: Condiviso da Writer COLONNA: Informazioni su Singers.Singer |
Utenti(3, 2020-11-01 12:34:56.426426+00:00) | 2,37 | 0,61 | 0,2573 | LOCK_MODE: ReaderShared COLUMN: users._exists1 LOCK_MODE: Condiviso da Writer COLUMN: users._exists1 |
1 _exists
è un campo interno utilizzato per verificare l'esistenza o meno di una determinata riga.
Conservazione dei dati
Come minimo, Spanner conserva i dati per ogni tabella per i seguenti periodi di tempo:
SPANNER_SYS.LOCK_STATS_TOP_MINUTE
eSPANNER_SYS.LOCK_STATS_TOTAL_MINUTE
: intervalli che coprono le 6 ore precedenti.SPANNER_SYS.LOCK_STATS_TOP_10MINUTE
eSPANNER_SYS.LOCK_STATS_TOTAL_10MINUTE
: intervalli che coprono i 4 giorni precedenti.SPANNER_SYS.LOCK_STATS_TOP_HOUR
eSPANNER_SYS.LOCK_STATS_TOTAL_HOUR
: intervalli relativi ai 30 giorni precedenti.
Risolvi i conflitti di blocco nel database utilizzando le statistiche di blocco
Puoi utilizzare SQL o la dashboard Lock Insights per visualizzare i conflitti di blocco nel database.
I seguenti argomenti mostrano come esaminare questi conflitti di blocco utilizzando il codice SQL.
Seleziona un periodo di tempo per l'indagine
Esaminerai le metriche di latenza del tuo database Spanner e scoprirai un periodo di tempo in cui la tua app riscontra un'elevata latenza e utilizzo della CPU. Ad esempio, il problema è iniziato alle 22:50 del 12 novembre 2020.
Determina se la latenza del commit della transazione è aumentata insieme al tempo di attesa per il blocco durante il periodo selezionato
I blocchi vengono acquisiti dalle transazioni pertanto, se i conflitti tra blocchi causano lunghi tempi di attesa, dovremmo essere in grado di vedere l'aumento della latenza di commit della transazione insieme all'aumento del tempo di attesa per il blocco.
Dopo aver selezionato un periodo di tempo per iniziare la nostra indagine, uniremo le
statistiche sulle transazioni TXN_STATS_TOTAL_10MINUTE
alle statistiche sui blocchi LOCK_STATS_TOTAL_10MINUTE
relative a quel periodo per aiutarci
a capire se l'aumento della latenza media del commit è contribuito
all'aumento del tempo di attesa per il blocco.
SELECT t.interval_end, t.avg_commit_latency_seconds, l.total_lock_wait_seconds
FROM spanner_sys.txn_stats_total_10minute t
LEFT JOIN spanner_sys.lock_stats_total_10minute l
ON t.interval_end = l.interval_end
WHERE
t.interval_end >= "2020-11-12T21:50:00Z"
AND t.interval_end <= "2020-11-12T23:50:00Z"
ORDER BY interval_end;
Prendiamo i seguenti dati come esempio dei risultati che otteniamo dalla nostra query.
interval_end | avg_commit_latency_seconds | total_lock_wait_seconds |
---|---|---|
12-11-2020 21:40:00-07:00 | 0,002 | 0,090 |
12-11-2020 21:50:00-07:00 | 0,003 | 0,110 |
12-11-2020 22:00:00-07:00 | 0,002 | 0,100 |
12-11-2020 22:10:00-07:00 | 0,002 | 0,080 |
12-11-2020 22:20:00-07:00 | 0,030 | 0,240 |
12-11-2020 22:30:00-07:00 | 0,034 | 0,220 |
12-11-2020 22:40:00-07:00 | 0,034 | 0,218 |
12-11-2020 22:50:00-07:00 | 3,741 | 780,193 |
12-11-2020 23:00:00-07:00 | 0,042 | 0,240 |
12-11-2020 23:10:00-07:00 | 0,038 | 0,129 |
12-11-2020 23:20:00-07:00 | 0,021 | 0,128 |
12-11-2020 23:30:00-07:00 | 0,038 | 0,231 |
I risultati precedenti mostrano un aumento significativo di avg_commit_latency_seconds
e total_lock_wait_seconds
durante lo stesso periodo di tempo dal 12/11/2020
22:40:00 al 12-11-2020 alle 22:50:00, per poi diminuire. Una cosa da notare è che avg_commit_latency_seconds
è il tempo medio trascorso solo per il passaggio di commit. D'altra parte, total_lock_wait_seconds
è il tempo di blocco
aggregato per il periodo, quindi sembra molto più lungo di quello
di commit della transazione.
Ora che abbiamo verificato che il tempo di attesa per il blocco è strettamente correlato all'aumento della latenza di scrittura, nel passaggio successivo analizzeremo quali righe e colonne causano la lunga attesa.
Scopri quali chiavi e colonne di riga hanno registrato lunghi tempi di attesa per il blocco nel periodo selezionato
Per scoprire quali chiavi e colonne di riga hanno riscontrato gli elevati tempi di attesa per il blocco durante il periodo in esame, eseguiamo una query sulla tabella LOCK_STAT_TOP_10MINUTE
, che elenca le chiavi e le colonne di riga che contribuiscono maggiormente al blocco dell'attesa.
La funzione CAST()
nella seguente query converte il campo
row_range_start_key BYTES in un STRING.
SELECT CAST(s.row_range_start_key AS STRING) AS row_range_start_key,
t.total_lock_wait_seconds,
s.lock_wait_seconds,
s.lock_wait_seconds/t.total_lock_wait_seconds frac_of_total,
s.sample_lock_requests
FROM spanner_sys.lock_stats_total_10minute t, spanner_sys.lock_stats_top_10minute s
WHERE
t.interval_end = "2020-11-12T22:50:00Z" and s.interval_end = t.interval_end;
row_range_start_key | total_lock_wait_seconds | lock_wait_seconds | frac_of_total | sample_lock_requests |
---|---|---|---|---|
Cantanti(32) | 780,193 | 780,193 | 1 | LOCK_MODE: Condiviso da Writer COLONNA: Informazioni su Singers.Singer LOCK_MODE: ReaderShared COLONNA: Informazioni su Singers.Singer |
Da questa tabella dei risultati, puoi vedere che il conflitto si è verificato nella tabella Singers
nella chiave SingerId=32. Singers.SingerInfo
è la colonna in cui si è verificato il
conflitto di blocco tra ReaderShared
e WriterShared
.
Si tratta di un tipo comune di conflitto quando una transazione tenta di leggere una determinata cella e l'altra transazione tenta di scrivere nella stessa cella. Ora conosciamo l'esatta cella di dati per cui le transazioni si contendono il blocco, quindi nel passaggio successivo identificheremo le transazioni che si contendono i blocchi.
Scoprire quali transazioni accedono alle colonne coinvolte nel conflitto di blocco
Per identificare le transazioni che presentano una latenza di commit significativa in un intervallo di tempo specifico a causa di conflitti di blocco, devi eseguire una query sulle seguenti colonne della tabella SPANNER_SYS.TXN_STATS_TOTAL_10MINUTE
:
fprint
read_columns
write_constructive_columns
avg_commit_latency_seconds
Devi filtrare in base alle colonne bloccate identificate dalla tabella SPANNER_SYS.LOCK_STATS_TOP_10MINUTE
:
Transazioni che leggono qualsiasi colonna che ha riscontrato un conflitto di blocco durante il tentativo di acquisire il blocco
ReaderShared
.Transazioni che scrivono in qualsiasi colonna che ha riscontrato un conflitto di blocco durante il tentativo di acquisire un blocco
WriterShared
.
SELECT
fprint,
read_columns,
write_constructive_columns,
avg_commit_latency_seconds
FROM spanner_sys.txn_stats_top_10minute t2
WHERE (
EXISTS (
SELECT * FROM t2.read_columns columns WHERE columns IN (
SELECT DISTINCT(req.COLUMN)
FROM spanner_sys.lock_stats_top_10minute t, t.SAMPLE_LOCK_REQUESTS req
WHERE req.LOCK_MODE = "ReaderShared" AND t.interval_end ="2020-11-12T23:50:00Z"))
OR
EXISTS (
SELECT * FROM t2.write_constructive_columns columns WHERE columns IN (
SELECT DISTINCT(req.COLUMN)
FROM spanner_sys.lock_stats_top_10minute t, t.SAMPLE_LOCK_REQUESTS req
WHERE req.LOCK_MODE = "WriterShared" AND t.interval_end ="2020-11-12T23:50:00Z"))
)
AND t2.interval_end ="2020-11-12T23:50:00Z"
ORDER BY avg_commit_latency_seconds DESC;
Il risultato della query è ordinato in base alla colonna avg_commit_latency_seconds
, in modo che tu possa vedere per prima la transazione con la latenza di commit più alta.
Fprint | read_columns | write_constructive_columns | avg_commit_latency_seconds |
---|---|---|---|
1866043996151916800 |
['Singers.SingerInfo', 'Singers.FirstName', 'Singers.LastName', 'Singers._exists'] |
["Singers.SingerInfo"] | 4,89 |
4168578515815911936 | [] | ["Singers.SingerInfo"] | 3,65 |
I risultati della query mostrano che due transazioni hanno tentato di accedere alla colonna Singers.SingerInfo
, che è la colonna in cui sono stati riscontrati conflitti di blocco durante il periodo di tempo.
Dopo aver identificato le transazioni che causano i conflitti di blocco, puoi analizzarle utilizzando la relativa impronta, fprint
, per identificare i potenziali problemi che hanno contribuito al conflitto di blocchi.
Dopo aver esaminato la transazione con fprint=1866043996151916800, puoi utilizzare le colonne read_columns
e write_constructive_columns
per identificare la parte del codice dell'applicazione che ha attivato la transazione. Puoi quindi visualizzare il codice DML sottostante che non filtra in base alla chiave primaria, SingerId
. Ciò ha causato
un'analisi completa della tabella e ha bloccato la tabella fino al commit della transazione.
Per risolvere il conflitto di blocchi, puoi procedere come segue:
- Utilizza una transazione di sola lettura per identificare i valori
SingerId
richiesti. - Utilizza una transazione di lettura/scrittura separata per aggiornare le righe per i valori
SingerId
richiesti.
Applicare le best practice per ridurre i conflitti tra blocchi
Nel nostro scenario di esempio, abbiamo potuto utilizzare le statistiche sui blocchi e sulle transazioni per limitare il problema a una transazione che non utilizzava la chiave primaria della nostra tabella durante gli aggiornamenti. Abbiamo pensato a delle idee per migliorare la transazione a seconda che conoscessimo o meno le chiavi delle righe da aggiornare in anticipo.
Quando esamini i potenziali problemi della tua soluzione, o anche quando progetti la soluzione, prendi in considerazione queste best practice per ridurre il numero di conflitti di blocco nel database.
Evita letture di grandi dimensioni all'interno delle transazioni di lettura-scrittura.
Se possibile, utilizza le transazioni di sola lettura perché non acquisiscono alcun blocco.
Evita scansioni complete delle tabelle in una transazione di lettura-scrittura. Ciò include la scrittura di un condizionale DML sulla chiave primaria o l'assegnazione di un intervallo di chiavi specifico quando si utilizza l'API Read.
Mantieni il periodo di blocco breve eseguendo il commit della modifica il prima possibile dopo aver letto i dati in una transazione di lettura-scrittura. Una transazione di lettura e scrittura garantisce che i dati rimangano invariati dopo la lettura dei dati fino a quando non esegui il commit della modifica. Per ottenere questo risultato, la transazione richiede il blocco delle celle di dati durante la lettura e durante il commit. Di conseguenza, se mantieni un periodo di blocco breve, è meno probabile che le transazioni presentino conflitti di blocco.
Preferisci le transazioni di piccole dimensioni rispetto a quelle di grandi dimensioni oppure prendi in considerazione il DML partizionato per le transazioni DML a lunga esecuzione. Una transazione a lunga esecuzione acquisisce un blocco per molto tempo, quindi ti consigliamo di suddividere una transazione che interessa migliaia di righe in più transazioni più piccole che aggiornano centinaia di righe, se possibile.
Se non hai bisogno della garanzia fornita da una transazione di lettura-scrittura, evita di leggere i dati nella transazione di lettura/scrittura prima di eseguire il commit della modifica, ad esempio leggendo i dati in una transazione separata di sola lettura. La maggior parte dei conflitti di blocco si verifica a causa di una forte garanzia, per garantire che i dati rimangano invariati tra la lettura e il commit. Quindi, se la transazione di lettura/scrittura non legge dati, non è necessario bloccare le celle per molto tempo.
Specificare solo l'insieme minimo di colonne richiesto in una transazione di lettura-scrittura. Poiché i blocchi di Spanner sono per cella di dati, quando una transazione di lettura-scrittura legge un numero eccessivo di colonne, acquisisce un blocco
ReaderShared
su queste celle. Ciò potrebbe causare conflitti di blocco quando altre transazioni acquisiscono un bloccoWriterShared
per le scritture nelle colonne in eccesso. Ad esempio, valuta la possibilità di specificare un insieme di colonne anziché*
alla lettura.Riduci al minimo le chiamate API in una transazione di lettura-scrittura. La latenza delle chiamate API potrebbe portare a contese del blocco in Spanner, poiché le chiamate API sono soggette a ritardi di rete e lato servizio. Ti consigliamo di effettuare chiamate API al di fuori delle transazioni di lettura-scrittura, quando possibile. Se devi eseguire chiamate API all'interno di una transazione di lettura-scrittura, assicurati di monitorare la latenza delle chiamate API per ridurre al minimo l'impatto sul periodo di blocco dell'acquisizione.
Passaggi successivi
- Scopri di più su altri strumenti di introspezione.
- Scopri altre informazioni sugli archivi Spanner per ogni database nella tabella dello schema di informazioni dei database.
- Scopri di più sulle best practice per SQL per Spanner.