Obteniendo "Tiempo de espera de bloqueo excedido; intente reiniciar la transacción "aunque no estoy usando una transacción

267

Estoy ejecutando la siguiente UPDATEdeclaración de MySQL :

mysql> update customer set account_import_id = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

No estoy usando una transacción, entonces, ¿por qué recibiría este error? Incluso intenté reiniciar mi servidor MySQL y no me ayudó.

La tabla tiene 406,733 filas.

Jason Swett
fuente

Respuestas:

211

Estás usando una transacción; autocommit no deshabilita las transacciones, solo las confirma automáticamente al final de la declaración.

Lo que está sucediendo es que algún otro hilo mantiene un bloqueo de registro en algún registro (¡está actualizando todos los registros de la tabla!) Durante demasiado tiempo, y su hilo se está agotando.

Puede ver más detalles del evento emitiendo un

SHOW ENGINE INNODB STATUS

después del evento (en sqleditor). Lo ideal es hacer esto en una máquina de prueba silenciosa.

MarkR
fuente
1
¿Hay alguna manera de guardar la salida en un archivo? Intenté SHOW ENGINE INNODB STATUS \ G> innodb_stat.txt pero no funciona.
yantaq
14
Desde la línea de comando: mysql [insertar credenciales] -e "MOSTRAR ESTADO INNODB DEL MOTOR \ G"> innodb_stat.txt
VenerableAgents
si muchos hilos (o procesos) de mysql están ocupados, por ejemplo, algunas consultas necesitan mucho tiempo, por lo que debe esperar algunas processpara estar inactivo. Si es así, podría obtener este error. Estoy en lo cierto?
zhuguowei
66
La ejecución de múltiples (2+) consultas de ACTUALIZACIÓN en la misma fila durante una sola transacción también provocará este error.
Okneloper
Para aquellos que usan Python MySQL Connector, utilícelos connection.commit()para confirmar INSERTo UPDATEacaba de pasar.
AER
334

CÓMO FORZAR EL DESBLOQUEO para tablas bloqueadas en MySQL:

Romper bloqueos como este puede causar que no se aplique la atomicidad en la base de datos en las instrucciones sql que causaron el bloqueo.

Esto es hackeo, y la solución adecuada es arreglar su aplicación que causó los bloqueos. Sin embargo, cuando hay dólares en juego, una patada rápida hará que las cosas vuelvan a moverse.

1) Ingrese MySQL

mysql -u your_user -p

2) Veamos la lista de tablas bloqueadas

mysql> show open tables where in_use>0;

3) Veamos la lista de los procesos actuales, uno de ellos es bloquear sus tablas.

mysql> show processlist;

4) Mata uno de estos procesos

mysql> kill <put_process_id_here>;
Eric Leschinski
fuente
14
Esto es peligroso y hackeo. Una solución adecuada es arreglar su aplicación.
Zenexer
71
Tonterías, esto te permite deshacer un error y luego arreglar la aplicación. Si pudiera darle a este tipo 100 votos para este problema que tenía que arreglar AHORA, lo haría.
Lizardx
77
Estoy de acuerdo con Lizardx. Esta fue una solución muy útil en la situación en la que no tuve el privilegio de llamar a SHOW ENGINE INNODB STATUS
Travis Schneeberger el
8
¿Cómo es peligroso matar una consulta de larga duración de esta manera ? El cliente que llama solo recibirá un error.
Xeoncross
77
@EricLeschinski Entiendo tu punto, pero tengo que preguntar por qué demonios usarías una base de datos descuidada como MySQL en un sistema crítico para la vida.
Xeoncross
96
mysql> set innodb_lock_wait_timeout=100

Query OK, 0 rows affected (0.02 sec)

mysql> show variables like 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 100   |
+--------------------------+-------+

Ahora active el bloqueo nuevamente. Tiene 100 segundos para emitir un SHOW ENGINE INNODB STATUS\Ga la base de datos y ver qué otra transacción está bloqueando la suya.

veen
fuente
8
Esta respuesta no explica por qué el autor de la pregunta recibe su error. ¿Podría explicar por qué, además de dar la respuesta?
Trineo el
55
+1 aunque esto no responde la pregunta directamente, para mí es una buena referencia para solucionar este problema.
Jossef Harush
1
@ArtB dev.mysql.com/doc/innodb/1.1/en/... En esencia el PO está recibiendo el error debido a un bloqueo fue llamado en la mesa y el tiempo transcurrido antes de terminar la transacción superó el lock_wait_timeoutvalor
fyrye
70

Eche un vistazo a si su base de datos está ajustada. Especialmente el aislamiento de transacciones. No es buena idea aumentar la variable innodb_lock_wait_timeout.

Verifique el nivel de aislamiento de la transacción de su base de datos en mysql cli:

mysql> SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation, @@session.transaction_isolation;
+-----------------------+-----------------+------------------------+
| @@GLOBAL.tx_isolation | @@tx_isolation  | @@session.tx_isolation |
+-----------------------+-----------------+------------------------+
| REPEATABLE-READ       | REPEATABLE-READ | REPEATABLE-READ        |
+-----------------------+-----------------+------------------------+
1 row in set (0.00 sec)

Puede obtener mejoras cambiando el nivel de aislamiento, use el oráculo como READ COMMITTED en lugar de REPEATABLE READ (valores predeterminados de InnoDB)

mysql> SET tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> 

También intente usar SELECCIONAR PARA ACTUALIZAR solo si es necesario.

saisyukusanagi
fuente
1
Esta es una gran solución para problemas de bloqueo.
olor a
3
Funciona muy bien para mí, la versión my.cnf es [mysqld] transacción-aislamiento = READ-COMMITTED
Benoit Gauthier
Solo una nota: MySQL 8 ha cambiado el nombre de la tx_isolationvariable a transaction_isolation.
xonya
Sin embargo, se deben tomar precauciones para saber en qué se está metiendo cuando cambia de aislamiento de lectura a LEER COMPROMETIDO. Puede terminar con datos sucios que tal vez desee evitar. Wikipedia Isoloation
huggie
27

Ninguna de las soluciones sugeridas funcionó para mí, pero esto sí.

Algo está bloqueando la ejecución de la consulta. Lo más probable es que otra consulta se actualice, inserte o elimine de una de las tablas de su consulta. Tienes que averiguar qué es eso:

SHOW PROCESSLIST;

Una vez que localice el proceso de bloqueo, búsquelo idy ejecute:

KILL {id};

Vuelva a ejecutar su consulta inicial.

BassMHL
fuente
Accidentalmente MATÉ todos los procesos enumerados con SHOW PROCESSLIST; Ahora recibo 500 error en phpmyadmin. ¿Ese error 500 está relacionado con matar estos procesos? En caso afirmativo, ¿cómo puedo reiniciarlo?
Dashrath el
Puedo ver lo que describe, sin embargo, matar el proceso no funciona. El comando del proceso se "mata", pero permanece en la lista de procesos.
Torsten
12

100% con lo que dijo MarkR. autocommit hace que cada declaración sea una transacción de una declaración.

SHOW ENGINE INNODB STATUSdebería darle algunas pistas sobre la razón del punto muerto. Eche un buen vistazo a su registro de consulta lento también para ver qué más está consultando la tabla e intente eliminar cualquier cosa que esté haciendo un escaneo de tabla completo. ¡El bloqueo de nivel de fila funciona bien, pero no cuando intentas bloquear todas las filas!

James C
fuente
5

¿Puede actualizar cualquier otro registro dentro de esta tabla, o esta tabla es muy utilizada? Lo que estoy pensando es que, mientras intenta adquirir un bloqueo, necesita actualizar este registro, el tiempo de espera establecido se ha agotado. Es posible que pueda aumentar el tiempo que puede ayudar.

John Kane
fuente
3
quizás innodb_lock_wait_timeoutenmy.cnf
oblig
1
Configuré en my.cnf: <br/> innodb_lock_wait_timeout = 120 <br/> El valor predeterminado es 50 para mysql 5.5. ¡Después de este cambio, no pude ver este problema en mis pruebas unitarias! Esto sucedió después de cambiar de proxool a grupo de tomcat jdbc. ¿Probablemente debido a más tiempo de transacción con el grupo de tomcat?
Campeón el
3

El número de filas no es enorme ... Cree un índice en account_import_id si no es la clave principal.

CREATE INDEX idx_customer_account_import_id ON customer (account_import_id);
gladiador
fuente
Dios mío ... esto me salvó. Realmente atornillé un DB de producción soltando un índice y esto lo solucionó. Gracias.
Nick Gotch
2

Si acaba de matar una consulta grande, llevará tiempo hacerlo rollback. Si emite otra consulta antes de que la consulta finalizada se revierta, es posible que obtenga un error de tiempo de espera de bloqueo. Eso es lo que me pasó. La solución fue solo esperar un poco.

Detalles:

Había emitido una consulta DELETE para eliminar aproximadamente 900,000 de aproximadamente 1 millón de filas.

Ejecuté esto por error (elimina solo el 10% de las filas): DELETE FROM table WHERE MOD(id,10) = 0

En lugar de esto (elimina el 90% de las filas): DELETE FROM table WHERE MOD(id,10) != 0

Quería eliminar el 90% de las filas, no el 10%. Así que eliminé el proceso en la línea de comando de MySQL, sabiendo que revertiría todas las filas que había eliminado hasta ahora.

Luego ejecuté el comando correcto inmediatamente y recibí un lock timeout exceedederror poco después. Me di cuenta de que el bloqueo en realidad podría ser el rollbackde la consulta eliminada que aún se realiza en segundo plano. Así que esperé unos segundos y volví a ejecutar la consulta.

Buttle Butkus
fuente
1

Asegúrese de que las tablas de la base de datos estén usando el motor de almacenamiento InnoDB y el nivel de aislamiento de transacciones READ-COMMITTED.

Puede verificarlo seleccionando @@ GLOBAL.tx_isolation, @@ tx_isolation; en la consola mysql.

Si no está configurado para READ-COMMITTED, debe configurarlo. Antes de configurarlo, asegúrese de tener privilegios SUPER en mysql.

Puede obtener ayuda de http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html .

Al configurar esto, creo que su problema se resolverá.


Es posible que también desee comprobar que no está intentando actualizar esto en dos procesos a la vez. Los usuarios (@tala) han encontrado mensajes de error similares en este contexto, tal vez verifique que ...

Ravi Chhatrala
fuente
1

Vengo de Google y solo quería agregar la solución que funcionó para mí. Mi problema era que estaba tratando de eliminar registros de una tabla enorme que tenía muchos FK en cascada, así que recibí el mismo error que el OP.

Inhabilité el autocommity luego funcionó simplemente agregando COMMITal final de la oración SQL. Según tengo entendido, esto libera el búfer poco a poco en lugar de esperar al final del comando.

Para seguir con el ejemplo del OP, esto debería haber funcionado:

mysql> set autocommit=0;

mysql> update customer set account_import_id = 1; commit;

No olvide autocommitvolver a activarlo nuevamente si desea salir de la configuración de MySQL como antes.

mysql> set autocommit=1;

Kamae
fuente
0

Tarde a la fiesta (como siempre), sin embargo, mi problema fue el hecho de que escribí algunos SQL incorrectos (siendo un novato) y varios procesos tenían un bloqueo en los registros <- no estoy seguro de la palabrería adecuada. Terminé teniendo que simplemente: SHOW PROCESSLISTy luego matar las ID usandoKILL <id>

Smitty
fuente
0

Este tipo de cosas me sucedió cuando estaba usando php language construct exit; en medio de la transacción. Luego, esta transacción se "cuelga" y necesita matar el proceso mysql (descrito anteriormente con la lista de procesos;)

TomoMiha
fuente
0

En mi caso, estaba ejecutando una consulta anormal para corregir datos. Si bloquea las tablas en su consulta, no tendrá que lidiar con el tiempo de espera de bloqueo:

LOCK TABLES `customer` WRITE;
update customer set account_import_id = 1;
UNLOCK TABLES;

Probablemente esta no sea una buena idea para el uso normal.

Para obtener más información, consulte: Manual de referencia de MySQL 8.0

Jeff Luyet
fuente
0

Me encontré con esto teniendo 2 conexiones Doctrine DBAL, una de ellas como no transaccional (para registros importantes), están destinadas a ejecutarse en paralelo sin depender una de la otra.

CodeExecution(
    TransactionConnectionQuery()
    TransactionlessConnectionQuery()
)

Mis pruebas de integración se incluyeron en transacciones para la reversión de datos después de la misma prueba.

beginTransaction()
CodeExecution(
    TransactionConnectionQuery()
    TransactionlessConnectionQuery() // CONFLICT
)
rollBack()

Mi solución fue deshabilitar la transacción de ajuste en esas pruebas y restablecer los datos db de otra manera.

Fabian Picone
fuente
-4

Tuve el mismo error, aunque solo estaba actualizando una tabla con una entrada, pero después de reiniciar mysql, se resolvió.

tubostico
fuente