Spanner fornisce statistiche sui blocchi che ti consentono di identificare la chiave di riga e le colonne della tabella che sono state le principali fonti di conflitti di blocco delle transazioni nel tuo 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 interfacce SQL, ad esempio:
Pagina Spanner Studio di un database nella console Google Cloud
Il comando
gcloud spanner databases execute-sql
La dashboard Insight sui blocchi
L'API
executeQuery
Gli altri metodi di lettura singola forniti da Spanner non supportanoSPANNER_SYS
.
Blocca le statistiche per chiave di riga
Le tabelle seguenti monitorano la chiave riga con il tempo di attesa più elevato:
SPANNER_SYS.LOCK_STATS_TOP_MINUTE
: chiavi di riga con i tempi di attesa della serratura più elevati durante intervalli di 1 minuto.SPANNER_SYS.LOCK_STATS_TOP_10MINUTE
: chiavi di riga con i tempi di attesa della serratura più elevati durante intervalli di 10 minuti.SPANNER_SYS.LOCK_STATS_TOP_HOUR
: chiavi di riga con i tempi di attesa della serratura più elevati durante intervalli di 1 ora
Queste tabelle hanno le seguenti proprietà:
Ogni tabella contiene dati per intervalli di tempo non sovrapposti della durata specificata dal nome della tabella.
Gli intervalli si basano sull'ora dell'orologio. Gli intervalli di 1 minuto terminano al minuto, quelli di 10 minuti terminano ogni 10 minuti a partire dall'ora e quelli di 1 ora terminano all'ora. Dopo ogni intervallo, Spanner raccoglie i dati da tutti i server e li rende disponibili nelle tabelle SPANNER_SYS poco dopo.
Ad esempio, alle 00:59:30, gli intervalli più recenti disponibili per le query SQL sono:
- 1 minuto: dalle 00:58:00 alle 00:58:59
- 10 minuti: 11:40:00-11:49:59
- 1 ora: dalle 10:00:00 alle 10:59:59 AM
Spanner raggruppa le statistiche in base all'intervallo di chiavi di riga iniziale.
Ogni riga contiene statistiche relative al tempo di attesa totale del blocco di un determinato intervallo di chiavi di riga iniziale per il quale Spanner acquisisce statistiche durante l'intervallo specificato.
Se Spanner non è in grado di memorizzare informazioni su ogni intervallo di chiavi di riga per le attese di blocco durante l'intervallo, il sistema dà la priorità all'intervallo di chiavi di riga con il tempo di attesa del blocco più elevato durante l'intervallo specificato.
Tutte le colonne delle tabelle sono nullable.
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 coinvolge un intervallo di righe, questo valore rappresenta la chiave iniziale dell'intervallo. Un segno più, + , indica un intervallo.
Per ulteriori informazioni, consulta Che cos'è una chiave iniziale dell'intervallo di righe.
|
LOCK_WAIT_SECONDS |
FLOAT64 |
Il tempo di attesa cumulativo per i conflitti di blocco registrato per tutte le colonne nell'intervallo della chiave di riga, in secondi. |
SAMPLE_LOCK_REQUESTS |
ARRAY<STRUCT<
|
Ogni voce di questo array corrisponde a una richiesta di blocco di esempio che
ha contribuito al conflitto di blocco in attesa di un blocco o
impedendo ad altre transazioni di acquisire il blocco, sulla chiave (intervallo) della riga specificata. Il numero massimo di campioni in questo array è 20.
Ogni sample contiene i seguenti tre campi:
|
Modalità di blocco
Le operazioni Spanner acquisiscono i blocchi quando fanno parte di una transazione di lettura/scrittura. Le transazioni di sola lettura non acquisiscono i blocchi. Spanner utilizza modalità di blocco diverse per massimizzare il numero di transazioni che hanno accesso a una determinata cella di dati in un determinato momento. Serrature diverse hanno caratteristiche diverse. Ad esempio, alcune chiavi possono essere condivise tra più transazioni, mentre altre no.
Un conflitto di blocco può verificarsi quando si tenta di acquisire uno dei seguenti modi di blocco in una transazione.
ReaderShared
Blocco: un blocco che consente ad altre letture di accedere ai dati fino a quando la transazione non è pronta per l'commit. Questo blocco condiviso viene acquisito quando una transazione di lettura-scrittura legge i dati.WriterShared
Blocco: questo blocco viene acquisito quando una transazione di lettura/scrittura tenta di eseguire il commit di una scrittura.Exclusive
Blocco: un blocco esclusivo viene acquisito quando una transazione di lettura/scrittura, che ha già acquisito un blocco condiviso con lettura, tenta di scrivere dati al termine della lettura. Una serratura esclusiva è un upgrade di una serraturaReaderShared
. Un blocco esclusivo è un caso speciale di una transazione che detiene contemporaneamente sia il bloccoReaderShared
sia il bloccoWriterShared
. Nessun'altra transazione può acquisire un blocco nella stessa cella.WriterSharedTimestamp
Blocco: un tipo speciale di bloccoWriterShared
che viene acquisito quando si inseriscono nuove righe in una tabella che ha un timestamp commit come parte della chiave primaria. Questo tipo di blocco impedisce ai partecipanti alla transazione di creare la stessa riga e, pertanto, di entrare in conflitto tra loro. Spanner aggiorna la chiave della riga inserita in modo che corrisponda al timestamp del commit della transazione che ha eseguito l'inserimento.
Per ulteriori informazioni sui tipi di transazioni e sui tipi di blocchi disponibili, consulta Transazioni.
Conflitti della 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 quando si scrive in celle esistenti o si inseriscono nuove righe senza timestamp. Di conseguenza, WriterSharedTimestamp
non può entrare in conflitto con altri tipi di serrature e questi scenari sono contrassegnati come Non applicabile nella tabella precedente.
L'unica eccezione è ReaderShared
, che può essere applicato a righe non esistenti
e, pertanto, potrebbe potenzialmente entrare in conflitto con WriterSharedTimestamp
. Ad esempio, una scansione completa della tabella blocca l'intera tabella anche per le righe che non sono state create, pertanto è 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 con conflitti di blocco. Il seguente schema 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 mostrato nella seguente tabella di chiavi di riga e intervalli di chiavi di riga, un intervallo è rappresentato con 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 |
---|---|
singers(2) | Tabella Cantanti con chiave SingerId=2 |
albums(2,1) | Tabella Album con chiave SingerId=2,AlbumId=1 |
songs(2,1,5) | Tabella Brani con chiave SingerId=2,AlbumId=1,TrackId=5 |
songs(2,1,5+) | Intervallo di chiavi della tabella Brani a partire da SingerId=2,AlbumId=1,TrackId=5 |
albums(2,1+) | Intervallo di chiavi della tabella Album a partire da SingerId=2,AlbumId=1 |
users(3, 2020-11-01 12:34:56.426426+00:00) | Tabella Utenti con chiave UserId=3, LastAccess=commit_timestamp |
Statistiche aggregate
SPANNER_SYS
contiene anche tabelle per archiviare i dati aggregati per le statistiche sui blocchi acquisiti da Spanner in un periodo di tempo specifico:
SPANNER_SYS.LOCK_STATS_TOTAL_MINUTE
: statistiche aggregate per tutte le attese per i blocchi durante intervalli di 1 minuto.SPANNER_SYS.LOCK_STATS_TOTAL_10MINUTE
: statistiche aggregate per tutte le attese di blocco durante intervalli di 10 minuti.SPANNER_SYS.LOCK_STATS_TOTAL_HOUR
: statistiche aggregate per tutte le attese dei blocchi durante intervalli di 1 ora.
Le tabelle delle statistiche aggregate hanno le seguenti proprietà:
Ogni tabella contiene dati per intervalli di tempo non sovrapposti della durata specificata dal nome della tabella.
Gli intervalli si basano sull'ora dell'orologio. Gli intervalli di 1 minuto terminano al minuto, quelli di 10 minuti terminano ogni 10 minuti a partire dall'ora e quelli di 1 ora terminano all'ora.
Ad esempio, alle 11:59:30, gli intervalli più recenti disponibili per le query SQL sulle statistiche di blocco aggregate sono:
- 1 minuto: dalle 00:58:00 alle 00:58:59
- 10 minuti: 11:40:00-11:49:59
- 1 ora: dalle 10:00:00 alle 10:59:59 AM
Ogni riga contiene le statistiche relative a tutte le attese dei blocchi nel database durante l'intervallo specificato, aggregate insieme. Esiste una sola riga per 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 ulteriori informazioni, consulta le 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 di attesa totale 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 sui blocchi per l'intervallo di 1 minuto precedente
La seguente query restituisce le informazioni sull'attesa del blocco per ogni chiave di riga con un conflitto di blocco, inclusa la frazione di conflitti di blocco totali, durante l'intervallo di tempo di 1 minuto più recente.
La funzione CAST()
converte il campo BYTES row_range_start_key in una STRINGA.
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 della query
row_range_start_key | total_lock_wait_seconds | lock_wait_seconds | frac_of_total | sample_lock_requests |
---|---|---|---|---|
Songs(2,1,1) | 2,37 | 1,76 | 0,7426 | LOCK_MODE: ReaderShared COLONNA: Singers.SingerInfo LOCK_MODE: WriterShared COLONNA: Singers.SingerInfo |
Users(3, 2020-11-01 12:34:56.426426+00:00) | 2,37 | 0,61 | 0,2573 | LOCK_MODE: ReaderShared COLONNA: utenti._exists1 LOCK_MODE: WriterShared COLONNA: utenti._exists1 |
1 _exists
è un campo interno utilizzato per verificare se una determinata riga esiste o meno.
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 che coprono i 30 giorni precedenti.
Risolvere i conflitti di blocco nel database utilizzando le statistiche sui blocchi
Puoi utilizzare SQL o la dashboard Approfondimenti su bloccaggi per visualizzare i conflitti di blocco nel database.
Gli argomenti che seguono mostrano come puoi esaminare questi conflitti di blocco utilizzando il codice SQL.
Seleziona un periodo di tempo da esaminare
Esamini le Metriche di latenza per il tuo database Spanner e scopri un periodo di tempo in cui la tua app presenta latenza e utilizzo della CPU elevati. Ad esempio, il problema ha iniziato a verificarsi intorno alle 22:50 del 12 novembre 2020.
Determina se la latenza del commit delle transazioni è aumentata insieme al tempo di attesa del blocco durante il periodo selezionato
I blocchi vengono acquisiti dalle transazioni, pertanto, se i conflitti di blocco causano tempi di attesa lunghi, dobbiamo essere in grado di vedere l'aumento della latenza del commit delle transazioni insieme all'aumento del tempo di attesa del 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
in quel periodo di tempo per aiutarci a capire se l'aumento della latenza media del commit è dovuto all'aumento del tempo di attesa del 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;
Prendi i seguenti dati come esempio dei risultati che otteniamo dalla nostra query.
interval_end | avg_commit_latency_seconds | total_lock_wait_seconds |
---|---|---|
2020-11-12 21:40:00-07:00 | 0,002 | 0,090 |
2020-11-12 21:50:00-07:00 | 0,003 | 0,110 |
2020-11-12 22:00:00-07:00 | 0,002 | 0,100 |
12-11-2020 22:10:00-07:00 | 0,002 | 0,080 |
2020-11-12 22:20:00-07:00 | 0,030 | 0,240 |
12-11-2020 22:30:00-07:00 | 0,034 | 0,220 |
2020-11-12 22:40:00-07:00 | 0,034 | 0,218 |
2020-11-12 22:50:00-07:00 | 3.741 | 780.193 |
2020-11-12 23:00:00-07:00 | 0,042 | 0,240 |
12-11-2020 23:10:00-07:00 | 0,038 | 0,129 |
2020-11-12 23:20:00-07:00 | 0,021 | 0,128 |
2020-11-12 23:30:00-07:00 | 0,038 | 0,231 |
I risultati precedenti mostrano un notevole aumento di avg_commit_latency_seconds
e total_lock_wait_seconds
nello stesso periodo di tempo, da 12-11-2020 22:40:00 a 12-11-2020 22:50:00, per poi diminuire. Tieni presente che avg_commit_latency_seconds
è il tempo medio impiegato solo per il passaggio di commit. D'altra parte, total_lock_wait_seconds
è il
tempo di blocco aggregato per il periodo, pertanto il tempo sembra molto più lungo rispetto al
tempo di commit della transazione.
Ora che abbiamo verificato che il tempo di attesa del blocco è strettamente correlato all'aumento della latenza di scrittura, nel passaggio successivo esamineremo le righe e le colonne che causano i lunghi tempi di attesa.
Scopri quali chiavi di riga e colonne hanno avuto tempi di attesa di blocco lunghi durante il periodo selezionato
Per scoprire quali chiavi di riga e colonne hanno registrato tempi di attesa elevati per i blocchi
durante il periodo in esame, eseguiamo una query sulla tabella LOCK_STAT_TOP_10MINUTE
che elenca le chiavi di riga e le colonne che contribuiscono maggiormente all'attesa
del blocco.
La funzione CAST()
nella seguente query converte il
campo BYTES row_range_start_key in una STRINGA.
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: WriterShared COLONNA: Singers.SingerInfo LOCK_MODE: ReaderShared COLONNA: Singers.SingerInfo |
Da questa tabella dei risultati, possiamo 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 sappiamo la cella di dati esatta per la quale le transazioni competono per la serratura, quindi nel passaggio successivo identificheremo le transazioni in competizione per le serrature.
Trova le transazioni che 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 query per
le 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 generato un conflitto di blocco durante il tentativo di acquisire il blocco
ReaderShared
.Transazioni che scrivono in qualsiasi colonna che ha generato un conflitto di blocco quando si tenta 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 viene ordinato in base alla colonna avg_commit_latency_seconds
in modo da visualizzare prima la transazione con la latenza di commit più elevata.
fprint | read_columns | scrivere_colonne_costruttive | 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 provato ad accedere alla colonnaSingers.SingerInfo
, ovvero la colonna con conflitti di blocco durante il periodo di tempo.
Una volta identificate le transazioni che causano i conflitti di blocco, puoi analizzarle utilizzando la loro impronta, fprint
, per identificare potenziali problemi che hanno contribuito al conflitto di blocco.
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 la DML sottostante che non filtra in base alla chiave principale, SingerId
. Ciò ha causato una scansione completa della tabella e ha bloccato la tabella fino al commit della transazione.
Per risolvere il conflitto di blocco, puoi:
- 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.
Applica le best practice per ridurre la contesa dei blocchi
Nel nostro scenario di esempio, siamo riusciti a utilizzare le statistiche di blocco e le statistiche sulle transazioni per restringere il problema a una transazione che non utilizzava la chiave primaria della nostra tabella durante l'esecuzione degli aggiornamenti. Abbiamo trovato delle idee per migliorare la transazione in base al fatto che conoscessimo o meno le chiavi delle righe che volevamo aggiornare.
Quando esamini potenziali problemi nella tua soluzione o anche quando la progetti, tieni presente 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 le scansioni complete della tabella in una transazione di lettura/scrittura. Ciò include la scrittura di un comando DML condizionale sulla chiave principale o l'assegnazione di un intervallo di chiavi specifico quando si utilizza l'API Read.
Mantieni breve il periodo di blocco eseguendo il commit della modifica il prima possibile dopo aver letto i dati in una transazione di lettura/scrittura. Una transazione di lettura/scrittura garantisce che i dati rimangano invariati dopo la lettura finché non esegui il commit della modifica. Per farlo, la transazione richiede il blocco delle celle di dati durante la lettura e la conferma. Di conseguenza, se puoi mantenere breve il periodo di blocco, è meno probabile che le transazioni abbiano conflitti di blocco.
Favorisci le transazioni di piccole dimensioni rispetto a quelle di grandi dimensioni oppure valuta la possibilità di utilizzare la DML partizionata per le transazioni DML di lunga durata. Una transazione di lunga durata acquisisce un blocco per molto tempo, quindi valuta la possibilità 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 applicare la modifica, ad esempio leggendo i dati in una transazione di sola lettura separata. La maggior parte dei conflitti di blocco si verifica a causa della garanzia forte, per garantire che i dati rimangano invariati tra la lettura e il commit. Pertanto, se la transazione di lettura/scrittura non legge alcun dato, non è necessario bloccare le celle per molto tempo.
Specifica 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 colonne eccessive, acquisisce un blocco
ReaderShared
su queste celle. Ciò potrebbe causare conflitti di blocco quando altre transazioni acquisiscono un bloccoWriterShared
sulle scritture nelle colonne eccessive. Ad esempio, valuta la possibilità di specificare un insieme di colonne anziché*
in fase di lettura.Riduci al minimo le chiamate API in una transazione di lettura/scrittura. La latenza delle chiamate API potrebbe portare a contese sui blocchi in Spanner, poiché le chiamate API sono soggette a ritardi della rete e del servizio. Ti consigliamo di effettuare chiamate API al di fuori delle transazioni di lettura/scrittura, se 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 acquisizione del blocco.
Passaggi successivi
- Scopri altri strumenti di introspezione.
- Scopri altre informazioni archiviate da Spanner per ogni database nella tabella schema delle informazioni dei database.
- Scopri di più sulle best practice per SQL per Spanner.