Fixação “O tempo limite de espera de bloqueio foi excedido; tente reiniciar a transação ”para uma tabela Mysql 'presa'?

131

A partir de um script, enviei uma consulta como essa milhares de vezes ao meu banco de dados local:

update some_table set some_column = some_value

Esqueci de adicionar a parte where, de modo que a mesma coluna foi definida com o mesmo valor para todas as linhas da tabela e isso foi feito milhares de vezes e a coluna foi indexada; portanto, o índice correspondente provavelmente foi atualizado muitas vezes .

Percebi que algo estava errado, porque demorou muito, então matei o script. Até reinicializei meu computador desde então, mas algo ficou preso na tabela, porque consultas simples demoram muito tempo para serem executadas e quando tento soltar o índice relevante, ele falha com esta mensagem:

Lock wait timeout exceeded; try restarting transaction

É uma tabela innodb, então a transação está presa provavelmente está implícita. Como posso corrigir esta tabela e remover a transação bloqueada?

Tom
fonte
3
Qual é a saída de SHOW FULL PROCESSLIST?
Wolph
Ele mostra apenas o comando SHOW FULL PROCESSLIST, nada mais. É um banco de dados de desenvolvimento local. Nada está funcionando nele. Eu recebi a mensagem de erro 'lock wait ..' na linha de comando quando tentei soltar o índice de lá.
Tom
Nesse caso, você provavelmente está criando 2 conexões separadas em transações diferentes que precisam esperar um pelo outro.
Wolph
Não criei nenhuma transação depois. Eu matei o script, reiniciei a máquina e entrei na linha de comando para olhar em volta. Nada mais usava o banco de dados, exceto o cliente de linha de comando mysql, portanto, algo deve ter ficado preso na tabela.
Tom
1
Pergunta relacionada: Como depurar o tempo limite de espera do bloqueio excedido?
Amir Ali Akbari

Respostas:

143

Eu tive um problema semelhante e resolvi-o verificando os threads em execução. Para ver os threads em execução, use o seguinte comando na interface da linha de comandos do mysql:

SHOW PROCESSLIST;

Também pode ser enviado a partir do phpMyAdmin se você não tiver acesso à interface da linha de comandos do mysql.
Isso exibirá uma lista de threads com os IDs correspondentes e o tempo de execução, para que você possa MATAR os threads que estão demorando muito para serem executados. No phpMyAdmin, você terá um botão para interromper os threads usando o KILL, se estiver usando a interface da linha de comandos, use o comando KILL seguido pelo ID do thread, como no exemplo a seguir:

KILL 115;

Isso encerrará a conexão para o encadeamento correspondente.

Mihai Crăiță
fonte
36
TOME NOTA! Isso foi mencionado por alguém em um dos muitos threads SO referentes a esse problema: Às vezes, o processo que bloqueou a tabela aparece como adormecido na lista de processos! Eu estava arrancando meus cabelos até matar todos os fios que estavam abertos no banco de dados em questão, dormindo ou não. Isso finalmente desbloqueou a tabela e deixou a consulta de atualização em execução. O comentarista mencionou algo como "Às vezes, um thread do MySQL bloqueia uma tabela e dorme enquanto espera que algo não relacionado ao MySQL aconteça."
Eric L.
(Eu adicionei a minha própria resposta à carne para fora esse fragmento pensamento aqui , sobre uma questão relacionada)
Eric L.
Isso me ajudou. Eu tive alguns threads adormecidos criados pelo recurso de gerenciamento / consulta do banco de dados PHPStorm.
Ejaz
Ótimo! Eu tinha um processo oculto desde 5 horas que eu conseguia identificar e matar.
Aldo Paradiso
2
isso não é uma solução, assim como a fita adesiva sobre uma ferida infectada é uma solução. você não está abordando o problema raiz subjacente.
user2914191
55

Você pode verificar as transações atualmente em execução com

SELECT * FROM `information_schema`.`innodb_trx` ORDER BY `trx_started`

Sua transação deve ser uma das primeiras, porque é a mais antiga da lista. Agora pegue o valor trx_mysql_thread_ide envie o KILLcomando:

KILL 1234;

Se não tiver certeza de qual transação é sua, repita a primeira consulta com muita frequência e veja quais transações persistem.

nlsrchtr
fonte
Pode ser necessário usar a conta root para executar o SQL para ver qual transação está realmente impedindo que outros acessem a tabela
tom10271 15/06
40

Verifique o status do InnoDB para bloqueios

SHOW ENGINE InnoDB STATUS;

Verifique as tabelas abertas do MySQL

SHOW OPEN TABLES WHERE In_use > 0;

Verificar transações pendentes do InnoDB

SELECT * FROM `information_schema`.`innodb_trx` ORDER BY `trx_started`; 

Verificar dependência de bloqueio - o que bloqueia o que

SELECT * FROM `information_schema`.`innodb_locks`;

Após investigar os resultados acima, você poderá ver o que está bloqueando o que.

A causa raiz do problema também pode estar no seu código - verifique as funções relacionadas, especialmente para anotações, se você usar JPA como o Hibernate.

Por exemplo, conforme descrito aqui , o uso incorreto da seguinte anotação pode causar bloqueios no banco de dados:

@Transactional(propagation = Propagation.REQUIRES_NEW) 
martoncsukas
fonte
4
Muito obrigado! Correndo SELECT * FROM information_schema.innodb_trx t JOIN information_schema.processlist p ON t.trx_mysql_thread_id = p.idrevelou o culpado: O thread bloqueio veio do meu no endereço IP ... eu tinha esquecido de fechar um console de depuração que eu tinha deixado no meio de uma transação ...
Elias Strehle
40

Isso começou a acontecer comigo quando o tamanho do meu banco de dados aumentou e eu estava fazendo muitas transações nele.

A verdade é que provavelmente existe uma maneira de otimizar suas consultas ou seu banco de dados, mas tente essas 2 consultas para solucionar o problema.

Rode isto:

SET GLOBAL innodb_lock_wait_timeout = 5000; 

E então isso:

SET innodb_lock_wait_timeout = 5000; 
D máximo
fonte
2
Link de referência: innodb_lock_wait_timeout
culix
1
Estou executando um banco de dados de 11 GB muito ocupado. Esta é a única coisa que funcionou para mim, obrigado!
dongemus
Lembre-se de alterar os valores para os valores anteriores se não quiser mantê-los lá para sempre.
Ricardo Martins
Isso significa que alguns dos meus usuários terão uma experiência mais lenta, certo?
Arnold Roa
9

Ao estabelecer uma conexão para uma transação, você adquire um bloqueio antes de executar a transação. Se não conseguir adquirir o bloqueio, tente por algum tempo. Se o bloqueio ainda não puder ser obtido, o erro de tempo de espera excedido será acionado. Por que você não poderá adquirir um bloqueio é que não está fechando a conexão. Portanto, quando estiver tentando obter um bloqueio pela segunda vez, não será possível adquiri-lo, pois sua conexão anterior ainda está fechada e mantendo o bloqueio.

Solução: feche a conexão ou setAutoCommit(true)(de acordo com o seu design) para liberar a trava.

user3388324
fonte
7

Reinicie o MySQL, ele funciona bem.

Mas cuidado, se essa consulta estiver emperrada, há um problema em algum lugar:

  • na sua consulta (char extraviado, produto cartesiano, ...)
  • registros muito numerosos para editar
  • junções ou testes complexos (MD5, substrings LIKE %...%, etc.)
  • problema de estrutura de dados
  • modelo de chave estrangeira (bloqueio de corrente / loop)
  • dados mal indexados

Como o @syedrakib disse, funciona, mas essa não é uma solução duradoura para a produção.

Cuidado: reiniciar pode afetar seus dados com um estado inconsistente.

Além disso, você pode verificar como o MySQL manipula sua consulta com a palavra-chave EXPLAIN e ver se há algo possível para acelerar a consulta (índices, testes complexos, ...).

Benj
fonte
OBRIGADO. você não resolveu meu problema diretamente, mas eu sofria de bloqueios de tabela e era muito ruim. Esse é o único post da Internet inteira, o que me leva à ideia de verificar as chaves estrangeiras. Então eu descobri que a chave da chave primária era 11 e as chaves estrangeiras 10. Não sei como isso poderia acontecer e por que tudo funcionava antes.
EscapeNetscape
@EscapeNetscape você é bem-vindo, estou feliz por esta resposta pouco você ajudou :)
Benj
3

Ir para processos no mysql.

Então, pode ver que ainda há tarefas funcionando.

Mate o processo específico ou aguarde até que o processo seja concluído.

Shemeer M Ali
fonte
7
Resolve o problema. Mas isso não pode ser uma solução para um servidor de produção LIVE ...... Como podemos gerar esse tratamento de impasse? Ou como podemos evitar que esse impasse aconteça?
Rakib
1
bem, acontece que mesmo com consultas mysql PERFEITAMENTE bem formadas e PERFEITAMENTE escapadas, que nem são escritas pelo desenvolvedor, mas pela interface de registros ativos da estrutura, problemas de tempo limite de espera de bloqueio AINDA podem acontecer. Então, eu não escrevendo a consulta mysql adequada é um fator aqui.
Rakib
1

Encontrei o mesmo problema com uma declaração de "atualização". Minha solução foi simplesmente executar as operações disponíveis no phpMyAdmin para a tabela. Otimizei, lavei e desfragmentei a tabela (não nessa ordem). Não há necessidade de descartar a tabela e restaurá-la do backup para mim. :)

O menino da ciência
fonte
1
Isso pode resolver o problema. Mas ter que fazer isso toda vez que esse erro ocorre não pode ser uma solução para um servidor de produção LIVE ...... Como podemos gerar esse tratamento de impasse? Ou como podemos evitar que esse impasse aconteça?
Rakib
1

Eu tive o mesmo problema. Eu acho que foi um problema de impasse com o SQL. Você pode apenas forçar o fechamento do processo SQL no Gerenciador de tarefas. Se isso não corrigir, basta reiniciar o computador. Você não precisa soltar a tabela e recarregar os dados.

Kriver
fonte
Resolve o problema. Mas isso não pode ser uma solução para um servidor de produção LIVE ...... Como podemos gerar esse tratamento de impasse? Ou como podemos evitar que esse impasse aconteça?
Rakib
Reinicie o Apache e seus serviços (ou pelo menos o MySQL), sem necessidade de reinicialização
Amjo
1

Eu tive esse problema ao tentar excluir um determinado grupo de registros (usando o MS Access 2007 com uma conexão ODBC com o MySQL em um servidor web). Normalmente, eu excluiria certos registros do MySQL e depois os substituiria por registros atualizados (excluir em cascata vários registros relacionados, isso simplifica a exclusão de todos os registros relacionados para uma única exclusão de registro).

Tentei executar as operações disponíveis no phpMyAdmin para a tabela (otimizar, liberar, etc), mas estava recebendo uma permissão necessária para RELOAD o erro quando tentei liberar. Como meu banco de dados está em um servidor web, não foi possível reiniciar o banco de dados. Restaurar a partir de um backup não era uma opção.

Tentei executar a consulta de exclusão desse grupo de registros no acesso do cPanel mySQL na web. Recebeu a mesma mensagem de erro.

Minha solução: usei o MySQL Query Browser da Sun (Oracle) gratuito (que eu instalei anteriormente no meu computador) e executei a consulta de exclusão lá. Funcionou imediatamente, problema resolvido. Pude executar novamente a função usando o script Access usando a conexão ODBC Access to MySQL.

Mike Lane
fonte
-2

Corrigido.

Verifique se você não possui inserção de tipo de dados incompatível na consulta. Eu tive um problema em que estava tentando "dados do agente do navegador do usuário" VARCHAR(255)e tendo problemas com esse bloqueio, no entanto, quando eu o alterei para TEXT(255)corrigi-lo.

Portanto, provavelmente é uma incompatibilidade de tipo de dados.

Hiren Raj
fonte
-151

Resolvi o problema descartando a tabela e restaurando-a do backup.

Tom
fonte
20
Aliás, essa resposta ganha a honra de ser a resposta "Aceita" de menor pontuação de todos os tempos da SO! Ash
ashleedawg 04/11/19
1
Esta é também a resposta mais baixa em geral em geral
Bob Kerman