AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 293992
Accepted
Mark Amery
Mark Amery
Asked: 2021-06-10 02:29:01 +0800 CST2021-06-10 02:29:01 +0800 CST 2021-06-10 02:29:01 +0800 CST

Faça ALTER TABLE esperar pelo bloqueio sem bloquear mais nada

  • 772

Muitos ALTER TABLEcomandos do PostgreSQL, como adicionar uma nova coluna com um valor padrão , têm otimizações inteligentes nas versões mais recentes do PostgreSQL que permitem que eles sejam executados basicamente instantaneamente, mesmo em tabelas grandes, uma vez que o Postgres adquiriu brevemente um bloqueio na tabela .

Infelizmente, essa advertência final é importante. Um comando como este da postagem do blog vinculada

ALTER TABLE users ADD COLUMN credits bigint NOT NULL DEFAULT 0;

ainda precisa esperar por um bloqueio exclusivo na userstabela antes de poder ser executado, mesmo que seja executado instantaneamente assim que o bloqueio for adquirido. Pior, enquanto espera por esse bloqueio, ele bloqueia todas as gravações e leituras que envolvem a tabela.

Alguns passos simples para reproduzir isso (testado no Postgres 13.3):

  1. Em um psqlshell, crie uma tabela, inicie uma transação, faça uma leitura da tabela e não confirme:

    CREATE TABLE users (id SERIAL, name TEXT);
    INSERT INTO users (name) VALUES ('bob'), ('fred');
    START TRANSACTION;
    SELECT * FROM users WHERE id = 1;
    
  2. Deixe o primeiro shell aberto, abra um segundo e tente alterar a tabela:

    ALTER TABLE users ADD COLUMN credits bigint NOT NULL DEFAULT 0;
    

    Observe que esta consulta trava, esperando que a transação no primeiro shell seja confirmada.

  3. Abra um terceiro terminal e tente executar

    SELECT * FROM users WHERE id = 2;
    

    Observe que isso também trava; agora está bloqueado aguardando ALTER TABLEa conclusão do comando, que por sua vez é bloqueado aguardando a conclusão da primeira transação.

Parece que a maioria ou todos os ALTER TABLEcomandos se comportam assim. Mesmo que a operação em si seja muito rápida ou possa ser executada sem manter um bloqueio para toda a operação, ALTER TABLEainda precisa adquirir brevemente um bloqueio exclusivo na tabela antes de iniciar seu trabalho e, enquanto espera por esse bloqueio, todas as outras instruções que tocar na mesa - até lê! - estão bloqueados.

Desnecessário dizer que esse comportamento é bastante problemático se você deseja fazer alterações em uma tabela que ocasionalmente está envolvida em transações de longa duração. Se a ALTER TABLEinstrução for bloqueada por uma transação de longa duração que esteja mantendo qualquer tipo de bloqueio envolvendo a tabela no momento em que a ALTER TABLEinstrução for executada, todas as interações com essa tabela serão bloqueadas até o final de qualquer transação aleatória de longa duração. , e qualquer coisa que dependa dessa tabela provavelmente passa por um tempo de inatividade.

Existe uma solução canônica para este problema?

Uma solução grosseira que tentei é usar um script wrapper que tenta repetidamente executar a ALTER TABLEinstrução por meio de uma conexão com lock_timeoutum valor pequeno (por exemplo, 5 segundos). Se ALTER TABLEfalhar devido ao tempo limite de bloqueio, a transação é abortada e o script detecta o erro, aguarda um ou dois minutos e tenta todo o processo novamente. Isso evita o tempo de inatividade total, mas ainda tem implicações de desempenho, pois cada tentativa fracassada de executar a ALTER TABLEinstrução ainda bloqueia as consultas por alguns segundos.

O que eu realmente gostaria de fazer é, de alguma forma, dizer ao Postgres que quero que a ALTER TABLEinstrução aguarde um momento em que possa adquirir o bloqueio na tabela sem bloquear outras consultas nesse meio tempo. (Não me importo se isso significa esperar horas até finalmente chegar a um momento em que nenhuma outra consulta esteja tocando a mesa; se evitar bloquear outras consultas, é uma troca absolutamente aceitável.) Existe alguma maneira de fazer isso - talvez algum encantamento que posso incluir na ALTER TABLEdeclaração ou algum parâmetro de configuração que posso definir para alterar esse comportamento?

postgresql locking
  • 1 1 respostas
  • 2364 Views

1 respostas

  • Voted
  1. Best Answer
    jjanes
    2021-06-10T09:13:04+08:002021-06-10T09:13:04+08:00

    Infelizmente, não há uma ótima alternativa para apenas tentar novamente em um loop. Mas talvez você possa tornar a repetição mais inteligente. Quando preciso fazer isso e posso estar em um bloco de transação, pego o bloqueio explicitamente e uso a opção NOWAIT .

    mas ainda tem implicações de desempenho, já que cada tentativa fracassada de executar a instrução ALTER TABLE ainda bloqueia as consultas por alguns segundos.

    Você pode definir o valor do tempo limite para ser menor (muito menor) do que alguns segundos. Ou você pode usar NOWAIT, que deve ser a mesma coisa que definir lock_timeout para seu valor mais baixo possível, mas redefinindo automaticamente assim que o bloqueio for adquirido (relevante no caso de transações com várias instruções).

    O que eu realmente gostaria de fazer é, de alguma forma, dizer ao Postgres que quero que a instrução ALTER TABLE aguarde um momento em que possa adquirir o bloqueio na tabela sem bloquear outras consultas nesse meio tempo.

    Sim, ter algumas opções melhores aqui seria bom. Pode ser controverso descobrir exatamente como isso seria, no entanto. Talvez algo como o bloqueio de baixa prioridade do MySQL, que se mantém na fila de espera, mas permite que outros garçons saltem sobre ele se o outro garçom puder obter imediatamente o bloqueio no modo desejado.

    • 3

relate perguntas

  • Posso ativar o PITR depois que o banco de dados foi usado

  • Práticas recomendadas para executar a replicação atrasada do deslocamento de tempo

  • Os procedimentos armazenados impedem a injeção de SQL?

  • Sequências Biológicas do UniProt no PostgreSQL

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve