O Spanner oferece estatísticas de bloqueio que permitem identificar a chave de linha e
colunas da tabela que eram as principais fontes de conflitos de bloqueio de transação na sua
no banco de dados durante um período específico. É possível recuperar essas estatísticas das
tabelas do sistema SPANNER_SYS.LOCK_STATS*
usando instruções SQL.
Disponibilidade
Os dados do SPANNER_SYS
estão disponíveis somente por meio de interfaces SQL. Por exemplo:
A página do Spanner Studio de um banco de dados no console do Google Cloud
O comando
gcloud spanner databases execute-sql
Bloquear insights painel
A API
executeQuery
Outros métodos de leitura única fornecidos pelo Spanner não têm suporte
SPANNER_SYS
:
Bloquear estatísticas por chave de linha
As tabelas a seguir rastreiam a chave de linha com o maior tempo de espera:
SPANNER_SYS.LOCK_STATS_TOP_MINUTE
: chaves de linha com os maiores tempos de espera de bloqueio durante intervalos de 1 minuto.SPANNER_SYS.LOCK_STATS_TOP_10MINUTE
: chaves de linha com os maiores tempos de espera de bloqueio durante intervalos de 10 minutos.SPANNER_SYS.LOCK_STATS_TOP_HOUR
: chaves de linha com os maiores tempos de espera de bloqueio durante intervalos de 1 hora
Essas tabelas têm as seguintes propriedades:
Cada tabela contém dados para intervalos de tempo não sobrepostos do comprimento especificado pelo nome da tabela.
Os intervalos são baseados em horas. Os intervalos de 1 minuto terminam no minuto, os de 10 minutos terminam a cada 10 minutos, começando na hora, e os intervalos de 1 hora terminam na hora. Após cada intervalo, o Spanner coleta dados de todos os servidores e, em seguida, disponibiliza os dados no SPANNER_SYS logo em seguida.
Por exemplo, às 11:59:30, os intervalos mais recentes disponíveis para as 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 iniciando o intervalo de chaves da linha.
Cada linha contém estatísticas para o tempo total de espera de bloqueio de um determinado intervalo de chaves de linha inicial para o qual o Spanner captura estatísticas durante o intervalo especificado.
Se o Spanner não puder armazenar informações sobre cada intervalo de chaves de linha para esperas de bloqueio durante o intervalo, o sistema vai priorizar o intervalo de chaves de linha com o maior tempo de espera de bloqueio durante o intervalo especificado.
Todas as colunas nas tabelas são anuláveis.
Esquema de tabela
Nome da coluna | Tipo | Descrição |
---|---|---|
INTERVAL_END |
TIMESTAMP |
Fim do intervalo de tempo em que os conflitos de bloqueio incluídos ocorreram. |
ROW_RANGE_START_KEY |
BYTES(MAX) |
Chave de linha em que ocorreu o conflito de bloqueio. Quando o conflito
envolve um intervalo de linhas, esse valor representa a chave inicial
desse intervalo. Um sinal de adição, + , significa um intervalo.
Para mais informações,
consulte O que é uma chave de início de intervalo de linhas.
|
LOCK_WAIT_SECONDS |
FLOAT64 |
O tempo de espera de bloqueio cumulativo de conflitos de bloqueio registrado para todas as colunas no intervalo de chaves de linha, em segundos. |
SAMPLE_LOCK_REQUESTS |
ARRAY<STRUCT<
|
Cada entrada nessa matriz corresponde a uma solicitação de bloqueio de amostra que
contribuiu para o conflito de bloqueios ao aguardar um bloqueio ou
bloquear outras transações para que elas não façam o bloqueio na chave de linha
especificada (intervalo). O número máximo de amostras nesta matriz é 20.
Cada amostra contém os três campos a seguir:
|
Modos de bloqueio
As operações do Spanner adquirem bloqueios quando fazem parte de uma transação de leitura/gravação. As transações somente leitura não para adquirir bloqueios. O Spanner usa diferentes modos de bloqueio para maximizar número de transações que têm acesso a uma célula de dados específica em uma determinada tempo de resposta. Bloqueios diferentes têm características diferentes. Por exemplo, alguns bloqueios podem ser compartilhados entre várias transações, enquanto outros não.
Um conflito de bloqueio pode ocorrer quando você tenta adquirir um dos seguintes modos de bloqueio em uma transação.
Bloqueio
ReaderShared
: um bloqueio que permite que outras leituras ainda acessem os dados até que a transação esteja pronta para confirmação. Este bloqueio compartilhado foi adquirido quando uma transação de leitura/gravação lê dados.Bloqueio
WriterShared
: é adquirido quando uma transação de leitura/gravação que tenta confirmar uma gravação.Bloqueio
Exclusive
: um bloqueio exclusivo é adquirido quando um bloqueio de leitura/gravação transação, que já adquiriu um bloqueio ReaderShared, tenta gravar após a conclusão da leitura. Um bloqueio exclusivo é um upgrade Bloqueio doReaderShared
. Um bloqueio exclusivo é um caso especial de uma transação. manter os bloqueiosReaderShared
eWriterShared
ao mesmo tempo. Nenhuma outra transação pode adquirir um bloqueio na mesma célula.Bloqueio
WriterSharedTimestamp
: um tipo especial de bloqueioWriterShared
que é adquirido ao inserir novas linhas em uma tabela que tem confirmação carimbo de data/hora como parte da chave primária. Esse tipo de bloqueio impede que os participantes da transação criem exatamente a mesma linha e, portanto, entram em conflito entre si. O Spanner atualiza a chave linha inserida para corresponder ao carimbo de data/hora de confirmação da transação que executou a inserção.
Para mais informações sobre os tipos de transações e os tipos de bloqueios disponíveis, consulte Transações.
Conflitos no modo de bloqueio
A tabela a seguir 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 relevante |
Exclusive |
Sim | Sim | Sim | Não relevante |
WriterSharedTimestamp |
Sim | Não relevante | Não relevante | Sim |
Os bloqueios WriterSharedTimestamp
são usados apenas ao inserir novas linhas com um
carimbo de data/hora como parte da chave primária. Os bloqueios WriterShared
e Exclusive
são
usados ao gravar em células existentes ou inserir novas linhas sem carimbos de data/hora. Como
resultado, WriterSharedTimestamp
não pode entrar em conflito com outros tipos de bloqueios, e
esses cenários são mostrados como Não relevante na tabela anterior.
A única exceção é ReaderShared
, que pode ser aplicado a linhas não existentes
e, portanto, pode entrar em conflito com WriterSharedTimestamp
. Por
exemplo, uma verificação de tabela completa bloqueia a tabela inteira mesmo para linhas que não foram
criadas. Portanto, é possível que ReaderShared
entre em conflito com
WriterSharedTimestamp
.
O que é uma chave de início de intervalo de linhas?
A coluna ROW_RANGE_START_KEY
identifica a chave primária composta ou
a chave primária inicial de um intervalo de linha que tem conflitos de bloqueio. O esquema
a seguir é 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 mostrado na tabela a seguir de intervalos de chave de linha e de chave de linha, um intervalo é representado por um sinal de adição, "+", na chave. A chave nesses casos representa a chave inicial de um intervalo de chaves em que ocorreu um conflito de bloqueio.
ROW_RANGE_START_KEY | Explicação |
---|---|
singers(2) | Tabela de cantores na chave SingerId=2 |
álbuns(2,1) | Tabela de álbuns na chave SingerId=2,AlbumId=1 |
Músicas(2,1,5) | Tabela de músicas na chave SingerId=2,AlbumId=1,TrackId=5 |
Músicas(2,1,5+) | Intervalo de chaves da tabela de músicas a partir de SingerId=2,AlbumId=1,TrackId=5 |
álbuns(2,1+) | Intervalo de chaves da tabela de álbuns a partir de SingerId=2,AlbumId=1 |
usuários(3, 2020-11-01 12:34:56.426426+00:00) | Tabela "Usuários" na chave UserId=3, LastAccess=commit_timestamp |
Agregar estatísticas
SPANNER_SYS
também contém tabelas para armazenar dados agregados de estatísticas de bloqueio
capturadas pelo Spanner em um período específico:
SPANNER_SYS.LOCK_STATS_TOTAL_MINUTE
: estatísticas agregadas para todos os bloqueios de espera durante intervalos de 1 minuto.SPANNER_SYS.LOCK_STATS_TOTAL_10MINUTE
: estatísticas agregadas para todos os bloqueios de espera 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 uma contém dados para intervalos de tempo não sobrepostos do comprimento especificado pelo nome da tabela.
Os intervalos são baseados em tempos de relógio. Os de 1 minuto terminam no minuto, os de 10 minutos terminam a cada 10 minutos, começando na hora, e os intervalos de 1 hora terminam na hora.
Por exemplo, às 11h59m30s, os intervalos mais recentes disponíveis para consultas SQL em estatísticas de bloqueio 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 para todas as esperas de bloqueio no banco de dados durante do intervalo especificado, agregados. Há apenas uma linha por intervalo de tempo.
As estatísticas capturadas nas tabelas
SPANNER_SYS.LOCK_STATS_TOTAL_*
incluem esperas de bloqueio que o Spanner não capturou nas tabelasSPANNER_SYS.LOCK_STATS_TOP_*
.Algumas colunas nessas 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 Spanner métricas.
Esquema de 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 registrados para todo o banco de dados, em segundos. |
Exemplo de consultas
Veja a seguir um exemplo de instrução SQL que pode ser usada para recuperar estatísticas de bloqueio. É possível executar essas instruções SQL usando as bibliotecas de cliente, o gcloud spanner ou o console do Google Cloud.
Listar as estatísticas de bloqueio do intervalo anterior de um minuto
A consulta a seguir retorna 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 um minuto mais recente.
A função CAST()
converte o campo row_range_start_key BYTES
em uma 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;
Saída 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 COLUNA: Singers.SingerInfo LOCK_MODE: WriterShared COLUNA: Singers.SingerInfo |
Usuários(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 uma
determinada linha existe ou não.
Retenção de dados
No mínimo, o Spanner mantém os dados de cada tabela pelo período a seguir períodos:
SPANNER_SYS.LOCK_STATS_TOP_MINUTE
eSPANNER_SYS.LOCK_STATS_TOTAL_MINUTE
: intervalos que abrangem as seis horas anteriores.SPANNER_SYS.LOCK_STATS_TOP_10MINUTE
eSPANNER_SYS.LOCK_STATS_TOTAL_10MINUTE
: intervalos abrangendo os quatro dias anteriores.SPANNER_SYS.LOCK_STATS_TOP_HOUR
eSPANNER_SYS.LOCK_STATS_TOTAL_HOUR
: Intervalos que abrangem os 30 dias anteriores.
Resolver conflitos de bloqueio no banco de dados usando estatísticas de bloqueio
É possível usar o SQL ou a chave de bloqueio insights para visualizar conflitos de bloqueio no seu banco de dados.
Os tópicos a seguir mostram como investigar esses conflitos de bloqueio usando SQL o código-fonte.
Selecione um período para investigar
Analise as métricas de latência do banco de dados do Spanner e descubra um período em que o app está apresentando alta latência e uso da CPU. Por exemplo, o problema começou a acontecer por volta das 22h50. em 12 de novembro de 2020.
Determina se a latência de confirmação da transação aumentou junto com o tempo de espera de bloqueio durante o período selecionado
Os bloqueios são adquiridos pelas transações. Portanto, se os conflitos de bloqueio causarem longos tempos de espera, poderemos ver o aumento na latência da confirmação da transação com o aumento no tempo de espera do bloqueio.
Depois de selecionar um período para iniciar nossa investigação, associaremos as
estatísticas de transação TXN_STATS_TOTAL_10MINUTE
às estatísticas de bloqueio LOCK_STATS_TOTAL_10MINUTE
nesse período para nos
ajudar a entender se o aumento da latência média de confirmação é contribuído pelo
aumento do tempo de espera do bloqueio.
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 obtemos 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 | 3.741 | 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 substancial em avg_commit_latency_seconds
e total_lock_wait_seconds
no mesmo período de 12/11/2020
22:40:00 para 2020-11-12 22:50:00 e caiu depois disso. Uma coisa a ser
observada é que o avg_commit_latency_seconds
é o tempo médio gasto
apenas para a etapa de confirmação. Por outro lado, total_lock_wait_seconds
é o
tempo de bloqueio agregado do período, de modo que o tempo é muito mais longo do que o
tempo de confirmação da transação.
Agora que confirmamos que o tempo de espera do bloqueio está intimamente relacionado ao aumento na latência de gravação, vamos investigar na próxima etapa quais linhas e colunas causam a longa espera.
Descobrir quais chaves de linha e colunas tiveram longos tempos de espera durante o período selecionado
Para descobrir quais chaves de linha e colunas tiveram os altos tempos de espera de bloqueio
durante o período que estamos investigando, consultamos a tabela LOCK_STAT_TOP_10MINUTE
,
que lista as chaves de linha e as colunas que contribuem mais para a espera
de bloqueio.
A função CAST()
na consulta a seguir converte o
campo row_range_start_key BYTES em uma 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 |
---|---|---|---|---|
Singers(32) | 780.193 | 780.193 | 1 | LOCK_MODE: WriterShared COLUNA: Singers.SingerInfo LOCK_MODE: ReaderShared COLUNA: Singers.SingerInfo |
Nesta tabela de resultados, podemos ver que o conflito aconteceu na tabela Singers
da chave SingerId=32. O Singers.SingerInfo
é a coluna em que ocorreu
o conflito de bloqueio entre ReaderShared
e WriterShared
.
Esse é um tipo comum de conflito quando há uma transação que tenta ler uma determinada célula e a outra transação está tentando gravar na mesma célula. Agora, sabemos a célula de dados exata que as transações estão concorrendo ao bloqueio. Portanto, na próxima etapa, vamos identificar as transações que concorrem pelos bloqueios.
Descubra quais transações estão acessando as colunas envolvidas no conflito de bloqueio
Para identificar as transações que estão com latência de confirmação significativa
em um intervalo de tempo específico devido a conflitos de bloqueio, é necessário consultar
as seguintes colunas da tabela
SPANNER_SYS.TXN_STATS_TOTAL_10MINUTE
:
fprint
read_columns
write_constructive_columns
avg_commit_latency_seconds
É necessário filtrar as colunas bloqueadas identificadas na tabela SPANNER_SYS.LOCK_STATS_TOP_10MINUTE
:
transações que leem qualquer coluna que gerou um conflito de bloqueio ao tentar receber o bloqueio
ReaderShared
.transações gravadas em qualquer coluna que tiveram um 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 é classificado pela coluna avg_commit_latency_seconds
para que você veja a
transação com a latência de confirmação mais alta primeiro.
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 acessar o
Singers.SingerInfo
, que é a coluna que apresentou conflitos de bloqueio durante o período.
Depois de identificar as transações que causam os conflitos de bloqueio, é possível analisar
as transações usando a impressão digital fprint
para identificar possíveis problemas
que contribuíram para o conflito de bloqueio.
Depois de analisar a transação com fprint=1866043996151916800, use o
Colunas read_columns
e write_constructive_columns
para identificar qual parte
do código do aplicativo acionou a transação. Em seguida, você pode consultar
à DML subjacente que não esteja filtrando a chave primária, SingerId
. Isso causou
uma verificação completa da tabela e a bloqueou até que a transação fosse confirmada.
Para resolver o conflito de bloqueio, você pode fazer o seguinte:
- Use uma transação somente leitura para identificar os valores
SingerId
obrigatórios. - Use uma transação de leitura/gravação separada para atualizar as linhas dos valores
SingerId
obrigatórios.
Aplicar as práticas recomendadas para reduzir a contenção de bloqueio
Em nosso cenário de exemplo, conseguimos usar estatísticas de bloqueio e estatísticas de transação para restringir nosso problema a uma transação que não estava usando a chave primária da tabela ao fazer atualizações. Nós tivemos ideias para melhorar a transação com base no fato de que sabíamos as chaves das linhas que gostaríamos de atualizar antecipadamente ou não.
Ao analisar possíveis problemas na solução ou até mesmo ao projetar a solução, considere estas práticas recomendadas para reduzir o número de conflitos de bloqueio no seu banco de dados.
Use transações somente leitura sempre que possível, porque elas não adquirem nenhuma cadeados.
Evite verificações de tabela completas em uma transação de leitura/gravação. Isso inclui gravar uma condicional DML na chave primária ou atribuir um intervalo de chaves específico ao usar a API Read.
Mantenha o período de bloqueio curto, confirmando a alteração assim que ler os dados o máximo possível em uma transação de leitura/gravação. Uma transação de leitura e gravação garante que os dados permaneçam inalterados depois que você lê os dados até que você confirme a mudança. Para isso, a transação requer o bloqueio das células de dados durante a leitura e a confirmação. Como resultado, se você puder manter o período de bloqueio curto, as transações têm menos probabilidade de ter conflitos de bloqueio.
Favoreça transações pequenas em lugar de transações grandes ou considere usar DML particionada para transações de DML de longa duração. Uma longa duração transação adquire um bloqueio por um longo período, então considere interromper transação que conecta milhares de linhas em várias que atualizam centenas de linhas sempre que possível.
Se você não precisar da garantia fornecida por uma transação de leitura e gravação, evite ler os dados da transação de leitura e gravação antes de confirmar a alteração. Por exemplo, leia os dados em uma transação separada de somente leitura. A maioria dos conflitos de bloqueio ocorre devido à forte garantia, para garantir que os dados permaneçam inalterados entre a leitura e a confirmação. Portanto, se a transação de leitura/gravação não fizer quaisquer dados, ele não precisará bloquear as células por muito tempo.
Especificar apenas o conjunto mínimo de colunas necessário em uma operação de leitura/gravação transação. Como os bloqueios do Spanner são por célula de dados, quando uma de leitura/gravação lê colunas excessivas e adquire um
ReaderShared
bloquear nessas células. Isso pode causar conflitos de bloqueio quando outras transações adquirir um bloqueioWriterShared
nas gravações nas colunas em excesso. Por exemplo, considere especificar um conjunto de colunas em vez de*
na leitura.Minimizar chamadas de API em uma transação de leitura/gravação. A latência das chamadas de API pode levar a uma disputa de bloqueio no Spanner, já que elas estão sujeitas a atrasos de rede e de serviço. Recomendamos fazer chamadas de API fora de transações de leitura/gravação sempre que possível. Se você precisar executar chamadas de API em uma transação de leitura e gravação, monitore a latência das chamadas de API para minimizar o impacto no período de aquisição de bloqueio.
A seguir
- Saiba mais sobre outras ferramentas de introspecção.
- Saiba mais sobre outras informações que o Spanner armazena para cada banco de dados em o esquema de informações dos bancos de dados; tabela.
- Saiba mais sobre práticas recomendadas de SQL para no Spanner.