Fijación "Tiempo de espera de bloqueo excedido; intente reiniciar la transacción ”para una tabla Mysql 'atascada'?

131

Desde un script envié una consulta como esta miles de veces a mi base de datos local:

update some_table set some_column = some_value

Olvidé agregar la parte where, por lo que la misma columna se configuró con el mismo valor para todas las filas de la tabla y esto se hizo miles de veces y la columna se indexó, por lo que el índice correspondiente probablemente se actualizó muchas veces .

Noté que algo andaba mal, porque tardó demasiado, así que eliminé el guión. Incluso reinicié mi computadora desde entonces, pero algo se quedó atascado en la tabla, porque las consultas simples demoran mucho tiempo en ejecutarse y cuando intento soltar el índice relevante falla con este mensaje:

Lock wait timeout exceeded; try restarting transaction

Es una tabla innodb, por lo que la transacción atascada es probablemente implícita. ¿Cómo puedo arreglar esta tabla y eliminar la transacción atascada?

Tom
fuente
3
¿Cuál es la salida de SHOW FULL PROCESSLIST?
Wolph
Solo muestra el comando SHOW FULL PROCESSLIST, nada más. Es una base de datos de desarrollo local. No se está ejecutando nada. Recibí el mensaje de error 'lock wait ..' en la línea de comando cuando intenté soltar el índice desde allí.
Tom
En ese caso, probablemente esté creando 2 conexiones separadas en diferentes transacciones que tienen que esperar entre sí.
Wolph
No creé ninguna transacción después. Eliminé el script, reinicié la máquina e inicié sesión desde la línea de comandos para mirar alrededor. Nada más usó la base de datos, excepto el cliente de línea de comando mysql, por lo que algo debe haber quedado atascado en la tabla.
Tom
1
Pregunta relacionada: ¿Cómo depurar el tiempo de espera de bloqueo excedido?
Amir Ali Akbari

Respuestas:

143

Tuve un problema similar y lo resolví revisando los hilos que se están ejecutando. Para ver los subprocesos en ejecución, use el siguiente comando en la interfaz de línea de comando mysql:

SHOW PROCESSLIST;

También se puede enviar desde phpMyAdmin si no tiene acceso a la interfaz de línea de comando mysql.
Esto mostrará una lista de subprocesos con identificadores correspondientes y tiempo de ejecución, por lo que puede MATAR los subprocesos que están tardando demasiado en ejecutarse. En phpMyAdmin tendrá un botón para detener los hilos usando KILL, si está usando la interfaz de línea de comando solo use el comando KILL seguido del id del hilo, como en el siguiente ejemplo:

KILL 115;

Esto terminará la conexión para el hilo correspondiente.

Mihai Crăiță
fuente
36
¡TOMAR NOTA! Alguien mencionó esto en uno de los muchos subprocesos SO relacionados con este problema: a veces, el proceso que ha bloqueado la tabla aparece como inactivo en la lista de procesos. Me estaba arrancando el pelo hasta que maté todos los hilos que estaban abiertos en la base de datos en cuestión, dormidos o no. Eso finalmente desbloqueó la tabla y dejó que se ejecutara la consulta de actualización. El comentarista mencionó algo como "A veces un hilo de MySQL bloquea una mesa, luego duerme mientras espera que suceda algo no relacionado con MySQL".
Eric L.
(Agregué mi propia respuesta para desarrollar ese fragmento de pensamiento aquí , en una pregunta relacionada)
Eric L.
Esto me ayudo. Tuve un par de hilos dormidos creados por la función de gestión / consulta de la base de datos PHPStorm.
Ejaz
¡Excelente! Tuve un proceso oculto desde hace 5 horas que pude identificar y matar.
Aldo Paradiso
2
Esta no es una solución más que una cinta adhesiva sobre una herida infectada. no está abordando el problema raíz subyacente.
user2914191
55

Puede verificar las transacciones actualmente en ejecución con

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

Su transacción debería ser una de las primeras, porque es la más antigua de la lista. Ahora solo toma el valor trx_mysql_thread_idy envíale el KILLcomando:

KILL 1234;

Si no está seguro de qué transacción es suya, repita la primera consulta con mucha frecuencia y vea qué transacciones persisten.

nlsrchtr
fuente
Es posible que necesite usar una cuenta raíz para ejecutar ese SQL para ver qué transacción realmente está bloqueando el acceso de la otra tabla
tom10271
40

Verifique el estado de InnoDB para ver si hay bloqueos

SHOW ENGINE InnoDB STATUS;

Verifica las tablas abiertas de MySQL

SHOW OPEN TABLES WHERE In_use > 0;

Verificar transacciones pendientes de InnoDB

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

Comprobar dependencia de bloqueo: qué bloquea qué

SELECT * FROM `information_schema`.`innodb_locks`;

Después de investigar los resultados anteriores, debería poder ver qué está bloqueando qué.

La causa raíz del problema también puede estar en su código; compruebe las funciones relacionadas, especialmente para las anotaciones si usa JPA como Hibernate.

Por ejemplo, como se describe aquí , el mal uso de la siguiente anotación puede causar bloqueos en la base de datos:

@Transactional(propagation = Propagation.REQUIRES_NEW) 
martoncsukas
fuente
44
Muchas gracias! Running SELECT * FROM information_schema.innodb_trx t JOIN information_schema.processlist p ON t.trx_mysql_thread_id = p.idreveló al culpable: el hilo de bloqueo vino de mi dirección IP ...
Olvidé
40

Esto comenzó a sucederme cuando el tamaño de mi base de datos creció y estaba haciendo muchas transacciones en él.

La verdad es que probablemente haya alguna forma de optimizar sus consultas o su base de datos, pero pruebe estas 2 consultas para solucionar el problema.

Ejecuta esto:

SET GLOBAL innodb_lock_wait_timeout = 5000; 

Y luego esto:

SET innodb_lock_wait_timeout = 5000; 
Max D
fuente
2
Enlace de referencia: innodb_lock_wait_timeout
culix
1
Estoy ejecutando una base de datos de 11GB muy ocupada. Esto es lo único que me ha funcionado, ¡gracias!
dongemus
Solo recuerde cambiar los valores a sus valores anteriores si no desea mantenerlos allí para siempre.
Ricardo Martins
Esto significa que algunos de mis usuarios tendrán una experiencia más lenta, ¿verdad?
Arnold Roa
9

Cuando establece una conexión para una transacción, adquiere un bloqueo antes de realizar la transacción. Si no puede adquirir el bloqueo, intente por algún tiempo. Si aún no se puede obtener el bloqueo, se genera el error de tiempo de espera de bloqueo excedido. La razón por la que no podrá adquirir un bloqueo es que no está cerrando la conexión. Por lo tanto, cuando intente obtener un bloqueo por segunda vez, no podrá adquirir el bloqueo ya que su conexión anterior aún no está cerrada y mantiene el bloqueo.

Solución: cierre la conexión o setAutoCommit(true)(según su diseño) para liberar el bloqueo.

usuario3388324
fuente
7

Reinicie MySQL, funciona bien.

PERO tenga en cuenta que si dicha consulta está atascada, hay un problema en alguna parte:

  • en su consulta (char mal colocado, producto cartesiano, ...)
  • registros muy numerosos para editar
  • combinaciones o pruebas complejas (MD5, subcadenas LIKE %...%, etc.)
  • problema de estructura de datos
  • modelo de llave extranjera (bloqueo de cadena / bucle)
  • datos mal indexados

Como dijo @syedrakib, funciona, pero esta no es una solución de larga duración para la producción.

Cuidado: hacer el reinicio puede afectar sus datos con un estado inconsistente.

Además, puede verificar cómo MySQL maneja su consulta con la palabra clave EXPLAIN y ver si hay algo allí para acelerar la consulta (índices, pruebas complejas, ...).

Benj
fuente
GRACIAS. no resolviste mi problema directamente pero sufrí bloqueos de mesa y fue muy malo. Esa es la única publicación en Internet, lo que me lleva a la idea de verificar las claves externas. Entonces descubrí que la clave de la clave primaria era 11 y las claves externas 10. No sé cómo podría suceder eso y por qué todo funcionaba antes.
EscapeNetscape
@EscapeNetscape de nada, me alegro de que esta pequeña respuesta te haya ayudado :)
Benj
3

Ir a procesos en mysql.

Entonces puedo ver que hay una tarea que aún funciona.

Elimine el proceso en particular o espere hasta que se complete el proceso.

Shemeer M Ali
fuente
77
Soluciona el problema. Pero esto no puede ser una solución para un servidor de producción EN VIVO ...... ¿Cómo podemos generar este manejo de punto muerto? ¿O cómo podemos EVITAR que este punto muerto ocurra?
Rakib
1
bueno, sucede que incluso con consultas mysql PERFECTAMENTE bien formadas y PERFECTAMENTE escapadas que ni siquiera están escritas por el desarrollador sino por la interfaz de registros activos del marco, TODAVÍA pueden ocurrir problemas de tiempo de espera de bloqueo. Entonces, no escribo una consulta mysql adecuada es un factor aquí.
Rakib
1

Me encontré con el mismo problema con una declaración de "actualización". Mi solución fue simplemente ejecutar las operaciones disponibles en phpMyAdmin para la tabla. Optimicé, enjuagué y desfragmenté la tabla (no en ese orden). No es necesario dejar la tabla y restaurarla desde la copia de seguridad para mí. :)

El chico de la ciencia
fuente
1
Podría resolver el problema. Pero tener que hacer esto cada vez que se produce dicho error no puede ser una solución para un servidor de producción EN VIVO ...... ¿Cómo podemos generar este manejo de punto muerto? ¿O cómo podemos EVITAR que este punto muerto ocurra?
Rakib
1

Tuve el mismo problema. Creo que fue un problema de bloqueo con SQL. Puede forzar el cierre del proceso SQL desde el Administrador de tareas. Si eso no lo solucionó, simplemente reinicie su computadora. No necesita soltar la tabla y volver a cargar los datos.

kriver
fuente
Soluciona el problema. Pero esto no puede ser una solución para un servidor de producción EN VIVO ...... ¿Cómo podemos generar este manejo de punto muerto? ¿O cómo podemos EVITAR que este punto muerto ocurra?
Rakib
reiniciar Apache y sus servicios (o al menos MySQL), no es necesario reiniciar
Amjo
1

Tuve este problema al intentar eliminar un determinado grupo de registros (usando MS Access 2007 con una conexión ODBC a MySQL en un servidor web). Por lo general, eliminaría ciertos registros de MySQL y luego los reemplazaría con registros actualizados (eliminar en cascada varios registros relacionados, esto simplifica la eliminación de todos los registros relacionados para una sola eliminación de registros).

Traté de ejecutar las operaciones disponibles en phpMyAdmin para la tabla (optimizar, vaciar, etc.), pero estaba recibiendo un permiso necesario para RELOAD error cuando intenté vaciar. Como mi base de datos está en un servidor web, no pude reiniciar la base de datos. Restaurar desde una copia de seguridad no era una opción.

Intenté ejecutar la consulta de eliminación para este grupo de registros en el acceso cPanel mySQL en la web. Recibí el mismo mensaje de error.

Mi solución: utilicé el MySQL Query Browser gratuito de Sun (Oracle) (que instalé previamente en mi computadora) y ejecuté la consulta de eliminación allí. Funcionó de inmediato, problema resuelto. Luego pude realizar una vez más la función usando la secuencia de comandos Access usando la conexión ODBC Access to MySQL.

Mike Lane
fuente
-2

Arreglado.

Asegúrese de que no haya una inserción de tipo de datos no coincidente en la consulta. Tuve un problema por el que estaba intentando "datos del agente del navegador del usuario" VARCHAR(255)y tenía problemas con este bloqueo, pero cuando lo cambié a TEXT(255)él, lo solucioné.

Por lo tanto, lo más probable es que no coincidan los tipos de datos.

Hiren Raj
fuente
-151

Resolví el problema soltando la tabla y restaurándola desde la copia de seguridad.

Tom
fuente
20
Por cierto, ¡esta respuesta gana el honor de ser la respuesta "aceptada" de SOP más baja de todos los tiempos! 🏆
ashleedawg
1
Esta es también la respuesta con la puntuación más baja en general, por lo tanto
Bob Kerman