Estatísticas de bloqueios

O Spanner fornece estatísticas de bloqueio que lhe permitem identificar a chave da linha e as colunas da tabela que foram as principais origens de conflitos de bloqueio de transações na sua base de dados durante um período específico. Pode obter estas estatísticas das tabelas do sistema SPANNER_SYS.LOCK_STATS* através de declarações SQL.

Estatísticas do bloqueio de acesso

O Spanner fornece as estatísticas de bloqueio no esquema SPANNER_SYS. Pode usar as seguintes formas para aceder aos dados do SPANNER_SYS:

  • A página do Spanner Studio de uma base de dados na Google Cloud consola

  • O comando gcloud spanner databases execute-sql

  • O painel de controlo Bloquear estatísticas.

  • O método executeSql ou o método executeStreamingSql.

    Os seguintes métodos de leitura única fornecidos pelo Spanner não suportam o SPANNER_SYS:

    • Executar uma leitura forte a partir de uma única linha ou de várias linhas numa tabela.
    • Executar uma leitura desatualizada de uma única linha ou várias linhas numa tabela.
    • Leitura de uma única linha ou várias linhas num índice secundário.

Bloqueie estatísticas por chave da linha

As tabelas seguintes monitorizam a chave da linha com o tempo de espera mais elevado:

  • SPANNER_SYS.LOCK_STATS_TOP_MINUTE: chaves de linhas com os tempos de espera de bloqueio mais elevados durante intervalos de 1 minuto.

  • SPANNER_SYS.LOCK_STATS_TOP_10MINUTE: chaves de linhas com os tempos de espera de bloqueio mais elevados durante intervalos de 10 minutos.

  • SPANNER_SYS.LOCK_STATS_TOP_HOUR: chaves de linhas com os tempos de espera de bloqueio mais elevados durante intervalos de 1 hora

Estas tabelas têm as seguintes propriedades:

  • Cada tabela contém dados para intervalos de tempo não sobrepostos com a duração especificada no nome da tabela.

  • Os intervalos baseiam-se nas horas do relógio. Os intervalos de 1 minuto terminam no minuto, os intervalos de 10 minutos terminam a cada 10 minutos a partir da hora, e os intervalos de 1 hora terminam na hora. Após cada intervalo, o Spanner recolhe dados de todos os servidores e, em seguida, disponibiliza os dados nas tabelas SPANNER_SYS pouco depois.

    Por exemplo, às 11:59:30, os intervalos mais recentes disponíveis para consultas SQL são:

    • 1 minuto: 11:58:00–11:58:59
    • 10 minutos: 11:40:00–11:49:59
    • 1 hora: 10:00:00–10:59:59
  • O Spanner agrupa as estatísticas por intervalo de chaves de linhas iniciais.

  • Cada linha contém estatísticas do tempo de espera de bloqueio total de um intervalo de chaves de linhas inicial específico para o qual o Spanner captura estatísticas durante o intervalo especificado.

  • Se o Spanner não conseguir armazenar informações sobre todos os intervalos de chaves de linhas para as esperas de bloqueio durante o intervalo, o sistema dá prioridade ao intervalo de chaves de linhas com o tempo de espera de bloqueio mais elevado durante o intervalo especificado.

  • Todas as colunas nas tabelas são anuláveis.

Esquema da tabela

Nome da coluna Tipo Descrição
INTERVAL_END TIMESTAMP Fim do intervalo de tempo em que ocorreram os conflitos de bloqueio incluídos.
ROW_RANGE_START_KEY BYTES(MAX) A chave da linha onde ocorreu o conflito de bloqueio. Quando o conflito envolve um intervalo de linhas, este valor representa a chave inicial desse intervalo. Um sinal de mais, +, significa um intervalo. Para mais informações, consulte o artigo O que é uma chave de início do intervalo de linhas.
LOCK_WAIT_SECONDS FLOAT64 O tempo de espera de bloqueio cumulativo de conflitos de bloqueio registados para todas as colunas no intervalo de chaves de linhas, em segundos.
SAMPLE_LOCK_REQUESTS ARRAY<STRUCT<
  column STRING,
  lock_mode STRING,
   transaction_tag STRING>>
Cada entrada nesta matriz corresponde a um pedido de bloqueio de exemplo que contribuiu para o conflito de bloqueio ao aguardar um bloqueio ou impedir que outras transações assumam o bloqueio na chave (intervalo) da linha especificada. O número máximo de exemplos nesta matriz é 20.
Cada exemplo contém os seguintes três campos:
  • lock_mode: o modo bloqueio que foi pedido. Para mais informações, consulte o artigo Modos de bloqueio .
  • column: a coluna que encontrou o conflito de bloqueio. O formato deste valor é tablename.columnname.
  • transaction_tag: a etiqueta da transação que emitiu o pedido. Para mais informações sobre a utilização de etiquetas, consulte o artigo Resolução de problemas com etiquetas de transações.
Todos os pedidos de bloqueio que contribuíram para conflitos de bloqueio são amostrados uniformemente de forma aleatória, pelo que é possível que apenas metade de um conflito (o detentor ou o que está em espera) seja registado nesta matriz.

Modos de bloqueio

As operações do Spanner adquirem bloqueios quando fazem parte de uma transação de leitura/escrita. As transações só de leitura não adquirem bloqueios. O Spanner usa diferentes modos de bloqueio para maximizar o número de transações que têm acesso a uma célula de dados específica num determinado momento. As diferentes fechaduras têm características diferentes. Por exemplo, alguns bloqueios podem ser partilhados entre várias transações, enquanto outros não podem.

Pode ocorrer um conflito de bloqueio quando tenta adquirir um dos seguintes modos de bloqueio numa transação.

  • ReaderShared Bloqueio: um bloqueio que permite que outras leituras continuem a aceder aos dados até que a sua transação esteja pronta para ser confirmada. Este bloqueio partilhado é adquirido quando uma transação de leitura/escrita lê dados.

  • WriterShared Bloqueio: este bloqueio é adquirido quando uma transação de leitura/escrita tenta confirmar uma escrita.

  • Exclusive Bloqueio: é adquirido um bloqueio exclusivo quando uma transação de leitura/escrita, que já adquiriu um bloqueio ReaderShared, tenta escrever dados após a conclusão da leitura. Um cadeado exclusivo é uma atualização de um cadeado ReaderShared. Um bloqueio exclusivo é um caso especial de uma transação que detém o bloqueio ReaderShared e o bloqueio WriterShared ao mesmo tempo. Nenhuma outra transação pode adquirir um bloqueio na mesma célula.

  • WriterSharedTimestamp Bloqueio: um tipo especial de bloqueio WriterShared que é adquirido quando são inseridas novas linhas numa tabela que tem uma data/hora de confirmação como parte da chave primária. Este tipo de bloqueio impede que os participantes na transação criem exatamente a mesma linha e, por isso, entrem em conflito entre si. O Spanner atualiza a chave da linha inserida para corresponder à data/hora de confirmação da transação que realizou a inserção.

Para mais informações sobre os tipos de transações e os tipos de bloqueios disponíveis, consulte Transações.

Conflitos do modo de bloqueio

A tabela seguinte mostra os possíveis conflitos entre diferentes modos de bloqueio.

Modos de bloqueio ReaderShared WriterShared Exclusive WriterSharedTimestamp
ReaderShared Não Sim Sim Sim
WriterShared Sim Não Sim Não aplicável
Exclusive Sim Sim Sim Não aplicável
WriterSharedTimestamp Sim Não aplicável Não aplicável Sim

Os bloqueios WriterSharedTimestamp só são usados quando são inseridas novas linhas com uma data/hora como parte da respetiva chave primária. Os bloqueios WriterShared e Exclusive são usados quando escreve em células existentes ou insere novas linhas sem datas/horas. Como resultado, WriterSharedTimestamp não pode entrar em conflito com outros tipos de bloqueios e esses cenários são apresentados como Não aplicável na tabela anterior.

A única exceção é ReaderShared, que pode ser aplicada a linhas inexistentes e, por isso, pode entrar em conflito com WriterSharedTimestamp. Por exemplo, uma análise completa da tabela bloqueia toda a tabela, mesmo para linhas que não foram criadas, pelo que é possível que ReaderShared entre em conflito com WriterSharedTimestamp.

O que é uma chave de início do intervalo de linhas?

A coluna ROW_RANGE_START_KEY identifica a chave principal composta ou a chave principal inicial de um intervalo de linhas que tem conflitos de bloqueio. O esquema seguinte é usado para ilustrar um exemplo.

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);

Conforme mostra a tabela seguinte de chave da linha e intervalos de chaves da linha, um intervalo é representado com um sinal de mais "+" na chave. Nesses casos, a chave representa a chave inicial de um intervalo de chaves no qual ocorreu um conflito de bloqueio.

ROW_RANGE_START_KEY Explicação
cantores(2) Tabela Singers na chave SingerId=2
albums(2,1) Tabela de álbuns em key SingerId=2,AlbumId=1
songs(2,1,5) Tabela de músicas em key SingerId=2,AlbumId=1,TrackId=5
músicas(2,1,5+) Intervalo de chaves da tabela de músicas a começar em SingerId=2,AlbumId=1,TrackId=5
álbuns(2,1+) Intervalo de chaves da tabela de álbuns a começar em SingerId=2,AlbumId=1
users(3, 2020-11-01 12:34:56.426426+00:00) Tabela de utilizadores na chave UserId=3, LastAccess=commit_timestamp

Estatísticas agregadas

SPANNER_SYS também contém tabelas para armazenar dados agregados para estatísticas de bloqueio capturadas pelo Spanner num período específico:

  • SPANNER_SYS.LOCK_STATS_TOTAL_MINUTE: estatísticas agregadas para todas as esperas de bloqueio durante intervalos de 1 minuto.

  • SPANNER_SYS.LOCK_STATS_TOTAL_10MINUTE: estatísticas agregadas para todas as esperas de bloqueio durante intervalos de 10 minutos.

  • SPANNER_SYS.LOCK_STATS_TOTAL_HOUR: estatísticas agregadas para todas as esperas de bloqueio durante intervalos de 1 hora.

As tabelas de estatísticas agregadas têm as seguintes propriedades:

  • Cada tabela contém dados para intervalos de tempo não sobrepostos com a duração especificada no nome da tabela.

  • Os intervalos baseiam-se nas horas do relógio. Os intervalos de 1 minuto terminam no minuto, os intervalos de 10 minutos terminam a cada 10 minutos a partir da hora, e os intervalos de 1 hora terminam na hora.

    Por exemplo, às 11:59:30, os intervalos mais recentes disponíveis para consultas SQL sobre estatísticas de bloqueios agregadas são:

    • 1 minuto: 11:58:00–11:58:59
    • 10 minutos: 11:40:00–11:49:59
    • 1 hora: 10:00:00–10:59:59
  • Cada linha contém estatísticas de todas as esperas de bloqueio na base de dados durante o intervalo especificado, agregadas. Só existe uma linha por intervalo de tempo.

  • As estatísticas capturadas nas tabelas SPANNER_SYS.LOCK_STATS_TOTAL_* incluem tempos de espera de bloqueios que o Spanner não capturou nas tabelas SPANNER_SYS.LOCK_STATS_TOP_*.

  • Algumas colunas nestas tabelas são expostas como métricas no Cloud Monitoring. As métricas expostas são:

    • Tempo de espera de bloqueio

    Para mais informações, consulte as métricas do Spanner.

Esquema da tabela

Nome da coluna Tipo Descrição
INTERVAL_END TIMESTAMP Fim do intervalo de tempo em que ocorreu o conflito de bloqueio.
TOTAL_LOCK_WAIT_SECONDS FLOAT64 Tempo total de espera de bloqueio para conflitos de bloqueio registados para toda a base de dados, em segundos.

Consultas de exemplo

Segue-se um exemplo de uma declaração SQL que pode usar para obter estatísticas de bloqueio. Pode executar estas declarações SQL através das bibliotecas de cliente, do gcloud spanner ou da Google Cloud consola.

Indica as estatísticas de bloqueio do intervalo de 1 minuto anterior

A seguinte consulta devolve as informações de espera de bloqueio para cada chave de linha com um conflito de bloqueio, incluindo a fração do total de conflitos de bloqueio, durante o intervalo de tempo de 1 minuto mais recente.

A função CAST() converte o campo BYTES row_range_start_key numa 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;
Resultado da consulta
row_range_start_key total_lock_wait_seconds lock_wait_seconds frac_of_total sample_lock_requests
Músicas(2,1,1) 2,37 1,76 0,7426 LOCK_MODE: ReaderShared

COLUMN: Singers.SingerInfo

LOCK_MODE: WriterShared

COLUMN: Singers.SingerInfo
Users(3, 2020-11-01 12:34:56.426426+00:00) 2,37 0,61 0,2573 LOCK_MODE: ReaderShared

COLUMN: users._exists1

LOCK_MODE: WriterShared

COLUMN: users._exists1

1 _exists é um campo interno usado para verificar se existe ou não uma determinada linha.

Retenção de dados

No mínimo, o Spanner mantém os dados de cada tabela durante os seguintes períodos:

  • SPANNER_SYS.LOCK_STATS_TOP_MINUTE e SPANNER_SYS.LOCK_STATS_TOTAL_MINUTE: intervalos que abrangem as 6 horas anteriores.

  • SPANNER_SYS.LOCK_STATS_TOP_10MINUTE e SPANNER_SYS.LOCK_STATS_TOTAL_10MINUTE: intervalos que abrangem os 4 dias anteriores.

  • SPANNER_SYS.LOCK_STATS_TOP_HOUR e SPANNER_SYS.LOCK_STATS_TOTAL_HOUR: Intervalos que abrangem os 30 dias anteriores.

Resolva conflitos de bloqueio na sua base de dados através de estatísticas de bloqueio

Pode usar SQL ou o painel de controlo Lock insights para ver conflitos de bloqueio na sua base de dados.

Os tópicos seguintes mostram como pode investigar esses conflitos de bloqueio através de código SQL.

Selecione um período para investigar

Examina as métricas de latência da sua base de dados do Spanner e descobre um período em que a sua app está a registar uma latência e uma utilização da CPU elevadas. Por exemplo, o problema começou a ocorrer por volta das 22:50 a 12 de novembro de 2020.

Determinar se a latência de confirmação da transação aumentou juntamente com o tempo de espera do bloqueio durante o período selecionado

Os bloqueios são adquiridos por transações. Por isso, se os conflitos de bloqueios causarem longos tempos de espera, devemos conseguir ver o aumento na latência de confirmação da transação, juntamente com o aumento no tempo de espera do bloqueio.

Depois de selecionar um período para iniciar a nossa investigação, vamos juntar as estatísticas de transações TXN_STATS_TOTAL_10MINUTE com as estatísticas de bloqueios LOCK_STATS_TOTAL_10MINUTE nessa altura para nos ajudar a compreender se o aumento da latência de confirmação média se deve ao aumento do tempo de espera de bloqueios.

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;

Considere os seguintes dados como um exemplo dos resultados que recebemos da nossa consulta.

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

Os resultados anteriores mostram um aumento drástico no avg_commit_latency_seconds e total_lock_wait_seconds durante o mesmo período, de 12-11-2020 22:40:00 a 12-11-2020 22:50:00, e diminuiu depois. Um aspeto a ter em atenção é que o avg_commit_latency_seconds é o tempo médio gasto apenas na etapa de confirmação. Por outro lado, total_lock_wait_seconds é o tempo de bloqueio agregado para o período, pelo que o tempo parece muito superior ao tempo de confirmação da transação.

Agora que confirmámos que o tempo de espera do bloqueio está estreitamente relacionado com o aumento da latência de escrita, vamos investigar no passo seguinte que linhas e colunas causam a longa espera.

Descubra que chaves de linhas e colunas tiveram longos tempos de espera de bloqueio durante o período selecionado

Para saber que chaves de linhas e colunas registaram tempos de espera de bloqueio elevados durante o período que estamos a investigar, consultamos a tabela LOCK_STAT_TOP_10MINUTE, que apresenta as chaves de linhas e as colunas que mais contribuem para o tempo de espera de bloqueio.

A função CAST() na consulta seguinte converte o campo BYTES row_range_start_key num 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
Cantores(32) 780 193 780 193 1 LOCK_MODE: WriterShared

COLUMN: Singers.SingerInfo

LOCK_MODE: ReaderShared

COLUMN: Singers.SingerInfo

A partir desta tabela de resultados, podemos ver que o conflito ocorreu na tabela Singers na chave SingerId=32. Singers.SingerInfo é a coluna onde ocorreu o conflito de bloqueio entre ReaderShared e WriterShared.

Este é um tipo comum de conflito quando existe uma transação a tentar ler uma determinada célula e a outra transação está a tentar escrever na mesma célula. Agora, sabemos a célula de dados exata para a qual as transações estão a disputar o bloqueio. Por isso, no passo seguinte, vamos identificar as transações que estão a disputar os bloqueios.

Descubra que transações estão a aceder às colunas envolvidas no conflito de bloqueio

Para identificar as transações que estão a sofrer uma latência de confirmação significativa num intervalo de tempo específico devido a conflitos de bloqueio, tem de consultar as seguintes colunas da tabela SPANNER_SYS.TXN_STATS_TOTAL_10MINUTE:

  • fprint
  • read_columns
  • write_constructive_columns
  • avg_commit_latency_seconds

Tem de filtrar as colunas bloqueadas identificadas na tabela SPANNER_SYS.LOCK_STATS_TOP_10MINUTE:

  • Transações que leem qualquer coluna que tenha incorrido num conflito de bloqueio ao tentar adquirir o bloqueio ReaderShared.

  • Transações que escrevem em qualquer coluna que incorreu num conflito de bloqueio ao tentar adquirir um bloqueio 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;

O resultado da consulta é ordenado pela coluna avg_commit_latency_seconds para que veja primeiro a transação com a latência de confirmação mais elevada.

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

Os resultados da consulta mostram que duas transações tentaram aceder à coluna Singers.SingerInfo, que é a coluna que teve conflitos de bloqueio durante o período. Depois de identificar as transações que causam os conflitos de bloqueio, pode analisar as transações através da respetiva impressão digital fprint para identificar potenciais problemas que contribuíram para o conflito de bloqueio.

Depois de rever a transação com fprint=1866043996151916800, pode usar as colunas read_columns e write_constructive_columns para identificar que parte do código da sua aplicação acionou a transação. Em seguida, pode ver o DML subjacente que não está a filtrar pela chave primária, SingerId. Isto causou uma análise completa da tabela e bloqueou a tabela até a transação ser confirmada.

Para resolver o conflito de bloqueio, pode fazer o seguinte:

  1. Use uma transação de leitura para identificar os valores SingerId necessários.
  2. Use uma transação de leitura/escrita separada para atualizar as linhas com os valores SingerId necessários.

Aplique práticas recomendadas para reduzir a contenção de bloqueios

No nosso cenário de exemplo, conseguimos usar as estatísticas de bloqueio e as estatísticas de transações para restringir o nosso problema a uma transação que não estava a usar a chave primária da nossa tabela ao fazer atualizações. Criámos ideias para melhorar a transação com base no facto de sabermos ou não as chaves das linhas que queríamos atualizar antecipadamente.

Quando analisar potenciais problemas na sua solução ou mesmo quando a criar, considere estas práticas recomendadas para reduzir o número de conflitos de bloqueio na sua base de dados.

  • Evite leituras grandes em transações de leitura/escrita.

  • Use transações só de leitura sempre que possível, porque não adquirem bloqueios.

  • Evite análises completas de tabelas numa transação de leitura/escrita. Isto inclui escrever um DML condicional na chave principal ou atribuir um intervalo de chaves específico quando usar a API Read.

  • Mantenha o período de bloqueio curto confirmando a alteração assim que ler os dados numa transação de leitura/escrita. Uma transação de leitura/escrita garante que os dados permanecem inalterados depois de ler os dados até confirmar com êxito a alteração. Para o conseguir, a transação requer o bloqueio das células de dados durante a leitura e durante a confirmação. Como resultado, se conseguir manter o período de bloqueio curto, é menos provável que as transações tenham conflitos de bloqueio.

  • Dê preferência a transações pequenas em vez de transações grandes ou considere usar DML particionada para transações DML de longa duração. Uma transação de execução prolongada adquire um bloqueio durante muito tempo. Por isso, pondere dividir uma transação que afeta milhares de linhas em várias transações mais pequenas que atualizam centenas de linhas sempre que possível.

  • Se não precisar da garantia fornecida por uma transação de leitura/escrita, evite ler quaisquer dados na transação de leitura/escrita antes de confirmar a alteração, por exemplo, lendo os dados numa transação só de leitura separada. A maioria dos conflitos de bloqueio ocorre devido à garantia forte, para garantir que os dados permanecem inalterados entre a leitura e a confirmação. Assim, se a transação de leitura/escrita não ler nenhum dado, não precisa de bloquear as células durante muito tempo.

  • Especifique apenas o conjunto mínimo de colunas necessárias numa transação de leitura/escrita. Como os bloqueios do Spanner são por célula de dados, quando uma transação de leitura/escrita lê colunas excessivas, adquire um bloqueio ReaderShared nestas células. Isto pode causar conflitos de bloqueio quando outras transações adquirem um bloqueio WriterShared em gravações nas colunas excessivas. Por exemplo, considere especificar um conjunto de colunas em vez de * na leitura.

  • Minimize as chamadas API numa transação de leitura/escrita. A latência das chamadas da API pode levar a contenção de bloqueios no Spanner, uma vez que as chamadas da API estão sujeitas a atrasos na rede, bem como a atrasos do lado do serviço. Recomendamos que faça chamadas à API fora das transações de leitura/escrita sempre que possível. Se tiver de executar chamadas API numa transação de leitura/escrita, certifique-se de que monitoriza a latência das chamadas API para minimizar o impacto no período de aquisição do bloqueio.

  • Siga as práticas recomendadas de design de esquemas.

O que se segue?