A finalização de uma venda fica parada no caixa 01, e o balcão 01 continua consultando os produtos sem demora. A sugestão de reconstruir a tabela de produtos, porque uma manutenção resolveu uma lentidão antiga, trataria um defeito que ninguém observou, e o caso mostra como encontrar quem espera e quem bloqueia antes de qualquer intervenção.
O relato e as evidências
Às 10:14 do dia 8 de outubro, o caixa 01 da filial 01 informa que a finalização de uma venda está parada e que uma tentativa anterior, às 10:10, terminou com uma mensagem de tempo esgotado. O balcão 01 consulta produtos e preços normalmente. O atendente sugere a reconstrução da tabela de produtos. Há quatro observações iniciais:
- o serviço do MySQL 5.1 do servidor da loja está em execução e aceita conexões;
- a tabela produtos usa o InnoDB, com a chave primária na coluna id;
- o registro do caixa 01 mostra o erro 1205, de tempo de espera esgotado, na tentativa das 10:10;
- o CHECK TABLE da tabela produtos, feito no dia anterior, terminou com OK.
O erro 1205 indica que uma instrução esperou um bloqueio além do limite, de 50 segundos por padrão, e não aponta defeito na tabela. As consultas do balcão 01 continuam porque um SELECT comum lê a versão confirmada das linhas e não espera os bloqueios. O CHECK TABLE de ontem também não diz nada sobre a demora de hoje.
Continuam possíveis uma espera por bloqueio, uma consulta custosa e uma espera por outro recurso, como o disco. A reconstrução da tabela não distingue nenhuma dessas hipóteses e acrescenta uma operação pesada ao servidor em pleno movimento. O teste que separa as hipóteses é a observação das conexões e das transações enquanto o sintoma acontece.
Quem espera e quem bloqueia
Às 10:14:30, o administrador coleta a situação no servidor da loja, com uma conta que enxerga as conexões de todos os usuários. Como o MySQL 5.1 da loja não tem as tabelas de transações do information_schema, a coleta usa dois comandos:
SHOW FULL PROCESSLIST;: mostra cada conexão, com a origem, o estado, o tempo e o comando em execução;SHOW ENGINE INNODB STATUS;: mostra, na seção TRANSACTIONS, as transações abertas e as esperas por bloqueio.
A lista de conexões mostra duas conexões ligadas ao sintoma:
- Conexão 42: vem do caixa 01, no endereço 192.168.1.20, e executa há 29 segundos o comando
UPDATE produtos SET estoque = estoque - 1 WHERE id = 316; - Conexão 17: vem do próprio servidor da loja e aparece no estado Sleep há 378 segundos, sem comando em execução.
Na seção TRANSACTIONS, a transação da conexão 42 aparece em LOCK WAIT, com a linha TRX HAS BEEN WAITING 29 SEC FOR THIS LOCK TO BE GRANTED, à espera de um bloqueio de registro no índice PRIMARY da tabela produtos. A transação da conexão 17 aparece ativa há 390 segundos, com bloqueios e alterações registradas, e é a única outra transação ativa no servidor. Na versão 5.1, a seção mostra o bloqueio esperado, mas não diz qual transação o segura, e a ligação entre as duas conexões ainda é uma associação provável.
O estado Sleep não tira a conexão 17 da investigação. Ele mostra só que não há comando em execução, e o tempo da lista conta desde o último comando, e não desde o início da transação. A transação pode guardar alterações sem COMMIT, com os bloqueios mantidos. Em um servidor com as tabelas INNODB_TRX e INNODB_LOCK_WAITS, ou com o sys.innodb_lock_waits a partir do 5.7, a mesma coleta mostraria de forma direta qual conexão bloqueia.
Outros resultados pediriam outro caminho. Sem nenhuma transação em LOCK WAIT e com o comando em execução, o próximo teste seria o plano da consulta, o volume de linhas e os recursos do servidor. Uma conta sem permissão para ver as outras conexões mostraria uma lista incompleta, e a ausência da conexão que bloqueia não provaria a ausência do bloqueio.
A transação aberta e o alcance do erro
A conexão 17 pertence a uma ferramenta gráfica de consulta, aberta por um técnico em acesso remoto ao servidor da loja. O técnico confirma que, às 10:08, corrigiu o preço do produto 316 com o comando UPDATE produtos SET preco = 8.50 WHERE id = 316 e deixou a janela aberta à espera da validação do novo preço pela gerência. A ferramenta trabalha com a confirmação automática desligada, e a correção ficou pendente, sem COMMIT. O relato liga as duas conexões: a correção segura o bloqueio da linha do produto 316, a mesma linha que a venda precisa alterar.
O registro do caixa 01 mostra o desfecho da tentativa coletada:
2026-10-08T10:14:51-03:00 caixa=01 conexao=42 erro=12052026-10-08T10:14:51-03:00 caixa=01 conexao=42 venda=desfeita itens=mantidos_na_tela
No MySQL 5.1, por padrão, o erro 1205 desfaz só a instrução que esperou, e as alterações anteriores da transação continuam pendentes. A aplicação do caixa, depois do erro, desfaz a venda inteira e mantém os itens na tela para uma nova tentativa, e por isso nenhuma das duas tentativas deixou uma venda gravada pela metade. Sem esse tratamento, a transação do caixa continuaria aberta, e a decisão entre confirmar e desfazer dependeria do que ela já tinha gravado.
A liberação e a validação
Um COMMIT na conexão 17 liberaria o caixa, mas confirmaria um preço que ninguém validou, e a decisão sobre a correção é de quem responde por ela. Como a gerência ainda não validou o novo preço, o técnico desfaz a correção com ROLLBACK na própria ferramenta, pela mesma conexão. Só a conexão que abriu a transação pode confirmá-la ou desfazê-la, e o ROLLBACK resolve sem encerrar a conexão de ninguém. O KILL da conexão 17 teria o mesmo efeito sobre a transação e ficaria para o caso de o dono da conexão não estar disponível, com o registro do que seria desfeito.
Às 10:16, uma nova coleta não mostra nenhuma transação em LOCK WAIT, e a conexão 17 não tem mais transação ativa. O caixa 01 finaliza a venda, e a consulta pelo documento mostra uma única venda gravada, com os itens e com o estoque do produto 316 reduzido uma vez. As gravações do caixa 01 e do balcão 01 são acompanhadas até as 10:30, sem nova espera.
O resultado confirma que o bloqueio foi a causa imediata das esperas coletadas, e não permite afirmar que as lentidões de outros dias tiveram a mesma causa. A correção do preço volta depois da validação, em uma transação curta, com a conferência do resultado antes do COMMIT.
O registro do atendimento
O registro liga cada conclusão à evidência que a sustenta:
- Ocorrência: às 10:10 e às 10:14:51, a finalização da venda no caixa 01 terminou com o erro 1205, à espera de um bloqueio na tabela produtos;
- Evidências: a conexão 42, do caixa 01, esperava um bloqueio de registro no índice PRIMARY de produtos, e a conexão 17, em Sleep, mantinha desde as 10:08 uma correção de preço do produto 316 sem COMMIT;
- Correção: o técnico desfez a correção pendente com ROLLBACK, na própria ferramenta, porque o preço ainda não tinha sido validado;
- Validação: a venda foi finalizada às 10:16, com uma única gravação, e as gravações seguintes não tiveram espera;
- Pendências: a correção do preço depois da validação, em uma transação curta, e a revisão do procedimento que deixou a transação aberta à espera de uma decisão.
No suporte
Diante de uma gravação parada, convém separar quem espera de quem bloqueia antes de qualquer reconstrução ou reinício. A conexão em Sleep pode guardar uma transação aberta, e a decisão entre COMMIT e ROLLBACK depende do trabalho que ela guarda.
Para guardar
- Uma gravação pode esperar um bloqueio com a tabela íntegra e a consulta correta.
- A conexão em Sleep pode manter uma transação aberta, com os bloqueios.
- No MySQL 5.1 sem as tabelas de transações, a seção TRANSACTIONS mostra a espera, mas não diz quem segura o bloqueio.
- O erro 1205 desfaz só a instrução que esperou, e o tratamento da aplicação define o destino do resto da transação.
- Liberar a espera não autoriza confirmar um trabalho que ninguém validou.
Se o caixa 01 recebesse o erro 1213, e não o 1205, o que mudaria?
O erro 1213 indica um deadlock, um ciclo de esperas que o InnoDB resolve ao desfazer uma das transações. A transação do caixa teria sido desfeita por inteiro, e a aplicação precisaria repetir a venda do começo. A investigação seguiria para a seção LATEST DETECTED DEADLOCK do SHOW ENGINE INNODB STATUS, que mostra as transações e os comandos envolvidos no ciclo.
Se a tabela produtos usasse o MyISAM, o que a coleta mostraria?
O bloqueio seria da tabela inteira e duraria o tempo do comando, sem relação com as transações. No MySQL 5.1, os comandos à espera apareceriam no estado Locked da lista de conexões, e quem bloqueia costuma ser um comando em execução na mesma tabela, como um relatório longo. O SHOW ENGINE INNODB STATUS não mostraria essa espera, e o encerramento de uma gravação MyISAM não desfaria o que ela já tinha alterado.