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étodoexecuteStreamingSql
.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<
|
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:
|
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 cadeadoReaderShared
. Um bloqueio exclusivo é um caso especial de uma transação que detém o bloqueioReaderShared
e o bloqueioWriterShared
ao mesmo tempo. Nenhuma outra transação pode adquirir um bloqueio na mesma célula.WriterSharedTimestamp
Bloqueio: um tipo especial de bloqueioWriterShared
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 tabelasSPANNER_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
eSPANNER_SYS.LOCK_STATS_TOTAL_MINUTE
: intervalos que abrangem as 6 horas anteriores.SPANNER_SYS.LOCK_STATS_TOP_10MINUTE
eSPANNER_SYS.LOCK_STATS_TOTAL_10MINUTE
: intervalos que abrangem os 4 dias anteriores.SPANNER_SYS.LOCK_STATS_TOP_HOUR
eSPANNER_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:
- Use uma transação de leitura para identificar os valores
SingerId
necessários. - 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.
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 bloqueioWriterShared
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.
O que se segue?
- Saiba mais acerca de outras ferramentas de introspeção.
- Saiba mais sobre outras informações que o Spanner armazena para cada base de dados na tabela information_schema das bases de dados.
- Saiba mais sobre as práticas recomendadas de SQL para o Spanner.