O caso é o seguinte:
Ao usar Show innodb status para verificar o status do mecanismo, um problema de deadlock foi descoberto:
*** (1) TRANSACTION:
TRANSACTION 0 677833455, ACTIVE 0 seg, process no 11393, OS thread id 278546 start index read
tabelas mysql em uso 1, bloqueado 1
LOCK WAIT 3 estrutura(s) de bloqueio, tamanho de heap 320
ID de thread MySQL 83, ID de consulta 162348740 dcnet03 dcnet Pesquisando linhas para atualização de atualização
TSK_TASK set STATUS_ID=1064,UPDATE_TIME=now () onde STATUS_ID=1061 e MON_TIME
*** (1) ESPERANDO QUE ESTE BLOQUEIO SEJA CONCEDIDO:
RECORD LOCKS space id 0 page no 849384 n bits 208 índice `PRIMARY` da tabela `dcnet_db/TSK_TASK` trx id 0 677833455 lock_mode X bloqueia rec mas não gap esperando
Bloqueio de registro , heap no 92 REGISTRO FÍSICO: n_fields 11; bits de informação compactos 0
0: hex 80000000097629c; 0 @ ;; 3: hexadecimal 80000000000050b2; f;; 7: comprimento 23; 8616e642e706870; asc xxx.com/;; 8: hex 80000000000042b; 9: hex 474bfa 2b; ascN$;;
* * (2) TRANSAÇÃO:
TRANSAÇÃO 0 677833454, ATIVO 0 seg, processo nº 11397, ID de encadeamento do SO 344086 atualizando ou excluindo, encadeamento declarado dentro de
tabelas mysql do InnoDB 499 em uso 1, bloqueado 1
3 estrutura(s) de bloqueio, tamanho de heap 320, desfazer entradas de log 1
thread MySQL id 84, consulta id 162348739 dcnet03 dcnet Atualizando
atualização TSK_TASK set STATUS_ID=1067,UPDATE_TIME=now () onde ID em (9921180)
*** (2) MANTÉM O(S) BLOQUEIO(S):
RECORD LOCKS id do espaço 0 página no 849384 n bits 208 índice `PRIMARY` da tabela `dcnet_db/TSK_TASK` trx id 0 677833454 lock_mode X bloqueia rec mas não gap
Bloqueio de registro, heap no 92 REGISTRO FÍSICO: n_fields 11 ; formato compacto de informações 0
0: len; 8; hex 800000000097629c; asc b;; 1: hex 00002866eaee; c P;; 4: len 8 ; hexadecimal 800000000000502a; 0; asc uploadfire.com/hand.php;; 8: hex 80000000000042b;
8
)
;
lock_mode X bloqueia rec, mas não aguarda intervalo
Bloqueio de registro, heap no 395 REGISTRO FÍSICO: n_fields 3; bits de informação 0
0: len 8000000000976; 29c; ;;
*** ROLL BACK TRANSACTION (1)
Este problema de deadlock envolve a tabela TSK_TASK, que é usada parasalvar
tarefas demonitoramento
do sistema A seguir estão os campos e índices relevantes:
ID: chave primária;
Status da tarefa;
índice: KEY_TSKTASK_MONTIME2 (STATUS_ID, MON_TIME).
A análise mostra que as duas instruções envolvidas não devem envolver o mesmo registro TSK_TASK, então por que isso causa um impasse?
Depois de consultar a documentação do site oficial do MySQL, descobri que isso está relacionado ao mecanismo de indexação do MySQL. O mecanismo InnoDB do MySQL usa bloqueios em nível de linha. Meu entendimento original era que os registros são bloqueados diretamente, mas esse não é o caso.
Os pontos-chave são os seguintes:
em vez de bloquear registros, o índice é bloqueado
durante as operações UPDATE e DELETE, o MySQL não apenas bloqueia todos os registros de índice verificados pela condição WHERE, mas também bloqueia valores de chave adjacentes, a chamada próxima chave; bloqueio;
por exemplo, a instrução UPDATE TSK_TASK SET UPDATE_TIME = NOW() WHERE ID > 10000 bloqueará todos os registros com uma chave primária maior ou igual a 1000. Antes da instrução ser concluída, você não pode operar em registros com uma chave primária igual a 1000. para 10000;
quando o índice não-cluster (Quando um registro de índice não-cluster é bloqueado, o registro de índice de cluster relacionado também precisa ser bloqueado para concluir a operação correspondente.
Analisando as duas instruções SQL onde ocorreu o problema, não é difícil encontrar o problema:
quando "update TSK_TASK set STATUS_ID=1064,UPDATE_TIME=now() onde STATUS_ID=1061 e MON_TIME
Supondo que "update TSK_TASK set STATUS_ID=1067,UPDATE_TIME=now () where ID in (9921180)" seja executado quase simultaneamente, esta instrução primeiro bloqueia o índice do cluster (chave primária). também é necessário bloquear uma determinada parte de KEY_TSKTASK_MONTIME2.
Desta forma, a primeira instrução bloqueia o registro de KEY_TSKTASK_MONTIME2 e aguarda o índice de chave primária, enquanto a segunda instrução bloqueia o registro do índice de chave primária e aguarda o registro de KEY_TSKTASK_MONTIME2. Neste caso, ocorre um deadlock.
O autor resolveu o problema do impasse dividindo a primeira instrução:
primeiro encontre o ID qualificado: selecione o ID de TSK_TASK onde STATUS_ID=1061 e MON_TIME Neste ponto, o problema de impasse está completamente resolvido.