El caso es el siguiente:
Al usar Mostrar estado de innodb para verificar el estado del motor, se descubrió un problema de interbloqueo:
*** (1) TRANSACCIÓN:
TRANSACCIÓN 0 677833455, ACTIVO 0 segundos, proceso no 11393, ID de subproceso del sistema operativo 278546 lectura del índice inicial
tablas mysql en uso 1, bloqueadas 1
LOCK WAIT 3 estructuras de bloqueo, tamaño del montón 320
ID de subproceso MySQL 83, ID de consulta 162348740 dcnet03 dcnet Buscando filas para actualizar
TSK_TASK set STATUS_ID=1064,UPDATE_TIME=now () donde STATUS_ID=1061 y MON_TIME
*** (1) ESPERANDO QUE SE OTORGUE ESTE BLOQUEO:
RECORD LOCKS espacio id 0 página no 849384 n bits 208 índice `PRIMARY` de la tabla `dcnet_db/TSK_TASK` trx id 0 677833455 lock_mode X bloquea la grabación pero no espera el espacio
Bloqueo de registro , montón no 92 REGISTRO FÍSICO: n_fields 11; formato compacto; bits de información 0
0: len 8; hex 80000000097629c; asc b;; hex 00000d400401 10; @ ;; 3: len 8; hex 80000000000050b2; asc 800000000005426; f;; 7: len 23; hexadecimal 75706c6f6164666972652e636f6d2f6 8616e642e706870; asc xxx.com/; 8: len 8; hexadecimal 80000000000042b;; len 8000000000004e24; ascN$;;
** * (2) TRANSACCIÓN:
TRANSACCIÓN 0 677833454, ACTIVA 0 segundos, proceso no 11397, ID de subproceso del sistema operativo 344086 actualizando o eliminando, subproceso declarado dentro de
tablas mysql InnoDB 499 en uso 1, bloqueado 1
3 estructuras de bloqueo, tamaño de montón 320, Deshacer entradas de registro 1
ID de subproceso MySQL 84, ID de consulta 162348739 dcnet03 dcnet Actualización
de actualización TSK_TASK set STATUS_ID=1067,UPDATE_TIME=now () donde ID en (9921180)
*** (2) MANTIENE LOS BLOQUEOS:
REGISTRO BLOQUEA la identificación del espacio 0 página no 849384 n bits 208 índice `PRIMARY` de la tabla `dcnet_db/TSK_TASK` trx id 0 677833454 lock_mode X bloquea la grabación pero no el espacio
Bloqueo de registro, montón no 92 REGISTRO FÍSICO: n_fields 11 formato compacto bits de información 0
0: len 8; hex 800000000097629c; asc b;; 1: len 6; hex 00002866eaee; asc (f;; 2: len 7; hex 00000d40040110; asc @;; 3: len 8; hex 80000000000050b2; c P ;; 4: len 8 ; hex 80000000000502a; asc P*; 5: len 8; hex 800000000005426;; 7: len 23; 0; asc uploadfire.com/hand.php;; 8: len 8; hexadecimal 80000000000042b; 8; hexadecimal 8000000000004e24; asc N$;;
*** (2) ESPERANDO QUE SE CONCEDA ESTE BLOQUEO:
REGISTRO BLOQUEOS espacio id 0 página no 843102 n bits 600 índice `KEY_TSKTASK_MONTIME2` de la tabla `dcnet_db/TSK_TASK` trx id 0 677833454 lock_mode X bloquea la grabación pero no espera
el bloqueo del registro, montón no 395 REGISTRO FÍSICO: n_fields 3;
hex 800012412c66d29c; 7629c; asc b ;;
*** RETROCEDEMOS LA TRANSACCIÓN (1)
Este problema de interbloqueo involucra la tabla TSK_TASK,
que se utiliza para guardar las tareas demonitoreo
del sistema. Los siguientes son los campos e índices relevantes:
ID: clave primaria;
Estado de la tarea:
índice: KEY_TSKTASK_MONTIME2 (STATUS_ID, MON_TIME).
El análisis muestra que las dos declaraciones involucradas no deberían involucrar el mismo registro TSK_TASK, entonces, ¿por qué causa un punto muerto?
Después de consultar la documentación del sitio web oficial de MySQL, descubrí que esto está relacionado con el mecanismo de indexación de MySQL. El motor InnoDB de MySQL utiliza bloqueos a nivel de fila. Mi entendimiento original era que los registros se bloquean directamente, pero en realidad este no es el caso.
Los puntos clave son los siguientes:
en lugar de bloquear registros, el índice se bloquea
durante las operaciones ACTUALIZAR y ELIMINAR, MySQL no solo bloquea todos los registros de índice escaneados por la condición WHERE, sino que también bloquea los valores de clave adyacentes, la llamada clave siguiente; bloqueo,
por ejemplo, la declaración UPDATE TSK_TASK SET UPDATE_TIME = NOW() WHERE ID > 10000 bloqueará todos los registros con una clave primaria mayor o igual a 1000. Antes de que se complete la declaración, no puede operar en registros con una clave primaria igual. a 10000;
cuando el índice que no es del grupo (Cuando un registro de índice que no es del grupo está bloqueado, el registro del índice del grupo relacionado también debe bloquearse para completar la operación correspondiente.
Al analizar las dos declaraciones SQL donde ocurrió el problema, no es difícil encontrar el problema:
cuando "actualiza TSK_TASK establece STATUS_ID=1064,UPDATE_TIME=now () donde STATUS_ID=1061 y MON_TIME
Suponiendo que "actualizar TSK_TASK set STATUS_ID=1067,UPDATE_TIME=now () donde ID en (9921180)" se ejecuta casi simultáneamente, esta declaración primero bloquea el índice del clúster (clave principal). Dado que es necesario actualizar el valor de STATUS_ID. También es necesario bloquear una determinada parte de KEY_TSKTASK_MONTIME2 y algunos registros de índice.
De esta manera, la primera declaración bloquea el registro de KEY_TSKTASK_MONTIME2 y espera el índice de clave principal, mientras que la segunda declaración bloquea el registro del índice de clave principal y espera el registro de KEY_TSKTASK_MONTIME2. En este caso, se produce un punto muerto.
El autor resolvió el problema del punto muerto dividiendo la primera declaración:
primero busque la ID calificada: seleccione la ID de TSK_TASK donde STATUS_ID=1061 y MON_TIME < date_sub(now(), INTERVAL 30 minutos; luego actualice el estado: actualice TSK_TASK establezca STATUS_ID=); 1064 donde ID en (….)
En este punto, el problema del punto muerto está completamente resuelto.