Statistiche sui blocchi

Spanner fornisce statistiche di blocco che 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 istruzioni SQL.

Accedere alle statistiche di blocco

Spanner fornisce le statistiche sui blocchi nello schema SPANNER_SYS. Puoi utilizzare i seguenti metodi per accedere ai dati di SPANNER_SYS:

  • La pagina Spanner Studio di un database nella console Google Cloud

  • Il comando gcloud spanner databases execute-sql.

  • La dashboard Insight sui blocchi.

  • Il metodo executeSql o executeStreamingSql.

    I seguenti metodi di lettura singola forniti da Spanner non supportano SPANNER_SYS:

    • Esecuzione di una lettura coerente da una o più righe di una tabella.
    • Esecuzione di una lettura obsoleta da una o più righe di una tabella.
    • Lettura da una singola riga o da più righe in un indice secondario.

Statistiche sui blocchi per chiave di riga

Le tabelle seguenti 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 del blocco più elevati durante intervalli di 1 minuto.

  • SPANNER_SYS.LOCK_STATS_TOP_10MINUTE: chiavi di riga con i tempi di attesa del blocco più elevati durante intervalli di 10 minuti.

  • SPANNER_SYS.LOCK_STATS_TOP_HOUR: Chiavi di riga con i tempi di attesa del blocco 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 nel nome della tabella.

  • Gli intervalli si basano sugli orari. Gli intervalli di 1 minuto terminano al minuto, gli intervalli di 10 minuti terminano ogni 10 minuti a partire dall'ora e gli intervalli 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 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 per intervallo di chiavi di riga iniziale.

  • Ogni riga contiene statistiche sul tempo di attesa totale per il blocco di un intervallo di chiave di riga iniziale specifico per cui Spanner acquisisce statistiche durante l'intervallo specificato.

  • Se Spanner non è in grado di memorizzare informazioni su ogni intervallo di chiave di riga per le attese di blocco durante l'intervallo, il sistema assegna la priorità all'intervallo dichiave di rigaa con il tempo di attesa di blocco più elevato durante l'intervallo specificato.

  • Tutte le colonne delle tabelle sono annullabili.

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 di quell'intervallo. Un segno più, +, indica un intervallo. Per saperne di più, 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 registrati per tutte le colonne nell'intervallo di chiave di riga, in secondi.
SAMPLE_LOCK_REQUESTS ARRAY<STRUCT<
  column STRING,
  lock_mode STRING,
   transaction_tag STRING>>
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 di riga (intervallo) specificata. Il numero massimo di campioni in questo array è 20.
Ogni campione contiene i seguenti tre campi:
  • lock_mode: La modalità di blocco richiesta. Per maggiori informazioni, vedi Modalità di chiusura .
  • column: La colonna in cui si è verificato il conflitto di blocco. Il formato di questo valore è tablename.columnname.
  • transaction_tag: Il tag della transazione che ha emesso la richiesta. Per saperne di più sull'utilizzo dei tag, consulta Risoluzione dei problemi con i tag transazione.
Tutte le richieste di blocco che hanno contribuito ai conflitti di blocco vengono campionate in modo uniforme e casuale, quindi è possibile che in questo array venga registrata solo una metà di un conflitto (il titolare o l'attesa).

Modalità di blocco

Le operazioni Spanner acquisiscono blocchi quando fanno parte di una transazione di lettura/scrittura. Le transazioni di sola lettura non acquiscono 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. Serrature diverse hanno caratteristiche diverse. Ad esempio, alcuni blocchi possono essere condivisi tra più transazioni, mentre altri no.

Un conflitto di blocco può verificarsi 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.

  • WriterShared Blocco: questo blocco viene acquisito quando una transazione di lettura/scrittura tenta di 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 dopo il completamento della lettura. Una serratura esclusiva è un upgrade di una serratura ReaderShared. Un blocco esclusivo è un caso speciale di transazione che contiene contemporaneamente sia il blocco ReaderShared sia il blocco WriterShared. Nessun'altra transazione può acquisire blocchi sulla stessa cella.

  • WriterSharedTimestamp Blocco: un tipo speciale di blocco WriterShared che viene acquisito quando si inseriscono nuove righe in una tabella che include un timestamp di commit come parte della chiave primaria. Questo tipo di blocco impedisce ai partecipanti alla transazione di creare esattamente la stessa riga e, pertanto, di entrare in conflitto 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 saperne di più sui tipi di transazione e sui tipi di blocchi disponibili, consulta la sezione Transazioni.

Conflitti della modalità di blocco

La seguente tabella mostra i possibili conflitti tra le diverse modalità di chiusura.

Modalità di blocco ReaderShared WriterShared Exclusive WriterSharedTimestamp
ReaderShared No
WriterShared No Non applicabile
Exclusive Non applicabile
WriterSharedTimestamp Non applicabile Non applicabile

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 indicati come Non applicabile nella tabella precedente.

L'unica eccezione è ReaderShared, che può essere applicato a righe inesistenti 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, 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. 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 mostra la seguente tabella di chiave di riga e intervalli di chiave 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
cantanti(2) Tabella Singers con chiave SingerId=2
album(2,1) Tabella degli album con SingerId=2 e AlbumId=1
brani(2,1,5) Tabella Songs in corrispondenza di SingerId=2,AlbumId=1,TrackId=5
brani(2,1,5+) Intervallo di chiavi della tabella Songs a partire da SingerId=2,AlbumId=1,TrackId=5
album(2,1+) Intervallo di chiavi della tabella Albums a partire da SingerId=2,AlbumId=1
users(3, 2020-11-01 12:34:56.426426+00:00) Tabella degli utenti con UserId=3 e LastAccess=commit_timestamp

Statistiche aggregate

SPANNER_SYS contiene anche tabelle per archiviare i 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 tutte le attese di blocco 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 di blocco 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 nel nome della tabella.

  • Gli intervalli si basano sugli orari. Gli intervalli di 1 minuto terminano al minuto, gli intervalli di 10 minuti terminano ogni 10 minuti a partire dall'ora e gli intervalli 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: 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 statistiche per tutte le attese di blocco sul database durante l'intervallo specificato, aggregate insieme. È presente 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 tabelle SPANNER_SYS.LOCK_STATS_TOP_*.

  • Alcune colonne di queste tabelle vengono esposte come metriche in Cloud Monitoring. Le metriche esposte sono:

    • Tempo per attesa di blocco

    Per maggiori 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 Google Cloud console.

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 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 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
Brani(2,1,1) 2,37 1,76 0,7426 LOCK_MODE: ReaderShared

COLONNA: Singers.SingerInfo

LOCK_MODE: WriterShared

COLONNA: Singers.SingerInfo
Utenti(3, 2020-11-01 12:34:56.426426+00:00) 2,37 0,61 0.2573 LOCK_MODE: ReaderShared

COLONNA: users._exists1

LOCK_MODE: WriterShared

COLONNA: 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 e SPANNER_SYS.LOCK_STATS_TOTAL_MINUTE: intervalli che coprono le 6 ore precedenti.

  • SPANNER_SYS.LOCK_STATS_TOP_10MINUTE e SPANNER_SYS.LOCK_STATS_TOTAL_10MINUTE: intervalli che coprono i 4 giorni precedenti.

  • SPANNER_SYS.LOCK_STATS_TOP_HOUR e SPANNER_SYS.LOCK_STATS_TOTAL_HOUR: Intervalli che coprono i 30 giorni precedenti.

Risolvi i conflitti di blocco nel tuo database utilizzando le statistiche sui blocchi

Puoi utilizzare SQL o la dashboard Approfondimenti sui blocchi per visualizzare i conflitti di blocco nel database.

I seguenti argomenti 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 registra 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 di commit delle transazioni è aumentata insieme al tempo di attesa del blocco durante il periodo selezionato

I blocchi vengono acquisiti dalle transazioni, quindi, se i conflitti di blocco causano lunghi tempi di attesa, dovremmo essere in grado di vedere l'aumento della latenza di commit delle transazioni insieme all'aumento del tempo di attesa del blocco.

Dopo aver selezionato un periodo di tempo per iniziare l'indagine, uniremo le statistiche sulle transazioni TXN_STATS_TOTAL_10MINUTE con le statistiche sui blocchi LOCK_STATS_TOTAL_10MINUTE in quel periodo di tempo per aiutarci a capire se l'aumento della latenza media di 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 restituiti 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
2020-11-12 22:10:00-07:00 0,002 0,080
2020-11-12 22:20:00-07:00 0,030 0,240
2020-11-12 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 3741 780.193
2020-11-12 23:00:00-07:00 0,042 0,240
2020-11-12 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 aumento drastico di avg_commit_latency_seconds e total_lock_wait_seconds nello stesso periodo di tempo dal 12/11/2020 alle 22:40:00 al 12/11/2020 alle 22:50:00, per poi diminuire. Un aspetto 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 il tempo sembra molto più lungo del tempo di commit della transazione.

Ora che abbiamo confermato che il tempo di attesa del blocco è strettamente correlato all'aumento della latenza di scrittura, nel passaggio successivo esamineremo quali righe e colonne causano la lunga attesa.

Scopri quali chiavi di riga e colonne hanno avuto tempi di attesa per il blocco lunghi durante il periodo selezionato

Per scoprire quali chiavi di riga e colonne hanno registrato tempi di attesa elevati per il blocco 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 alla chiave SingerId=32. Singers.SingerInfo è la colonna in cui si è verificato il conflitto di blocco tra ReaderShared e WriterShared.

Questo è 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 la cella di dati esatta per la quale le transazioni contendono il blocco, quindi nel passaggio successivo identificheremo le transazioni che contendono i blocchi.

Trovare le transazioni che accedono alle colonne coinvolte nel conflitto di blocco

Per identificare le transazioni che riscontrano una latenza di commit significativa in un intervallo di tempo specifico a causa di conflitti di blocco, devi eseguire una 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 le colonne bloccate identificate dalla tabella SPANNER_SYS.LOCK_STATS_TOP_10MINUTE:

  • Transazioni che leggono qualsiasi colonna che ha generato un conflitto di blocco quando si tenta 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 per prima la transazione con la latenza di commit più elevata.

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, ovvero la colonna che ha avuto 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 il DML sottostante che non filtra in base alla chiave primaria, SingerId. Ciò ha causato una scansione completa della tabella e l'ha bloccata fino al commit della transazione.

Per risolvere il conflitto di blocco, puoi:

  1. Utilizza una transazione di sola lettura per identificare i valori SingerId richiesti.
  2. 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

Nello scenario di esempio, siamo riusciti a utilizzare le statistiche della serratura e delle transazioni per restringere il problema a una transazione che non utilizzava la chiave primaria della nostra tabella durante gli aggiornamenti. Abbiamo trovato idee per migliorare la transazione in base al fatto che conoscessimo o meno in anticipo le chiavi delle righe che volevamo aggiornare.

Quando esamini i 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.

  • Utilizza le transazioni di sola lettura quando possibile, perché non acquisiscono blocchi.

  • Evita le scansioni complete delle tabelle in una transazione di lettura/scrittura. Ciò include la scrittura di un'istruzione DML condizionale alla chiave primaria o l'assegnazione di un intervallo di chiavi specifico quando utilizzi 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 dei dati fino al commit della modifica. Per raggiungere questo obiettivo, la transazione richiede il blocco delle celle di dati durante la lettura e durante il commit. Di conseguenza, se riesci a mantenere breve il periodo di blocco, è meno probabile che le transazioni presentino conflitti di blocco.

  • Privilegia le transazioni di piccole dimensioni rispetto a quelle di grandi dimensioni o valuta la possibilità di utilizzare DML partizionato per le transazioni DML a esecuzione prolungata. Una transazione a esecuzione prolungata acquisisce un blocco per un lungo periodo di tempo, quindi valuta la possibilità di suddividere una transazione che tocca 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 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 il set minimo di colonne richieste 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 blocco WriterShared sulle scritture nelle colonne in eccesso. Ad esempio, valuta la possibilità di specificare un insieme di colonne anziché * in lettura.

  • Ridurre al minimo le chiamate API in una transazione di lettura/scrittura. La latenza delle chiamate API potrebbe causare contese di blocco in Spanner, in quanto 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, 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.

  • Segui le best practice di progettazione dello schema.

Passaggi successivi