2009-11-06 29 views
6

Supongo que este problema se aplica a interbloqueos, bloqueos en tiempo real, o simplemente bloquea el tiempo de espera de espera.¿Cómo soluciono un problema de bloqueo en MySQL?

Estoy tratando de averiguar qué consulta está causando un bloqueo que impide que se ejecute otra consulta. Oracle tiene (si la memoria sirve) una tabla LOCK a la que puede unirse para determinar qué consultas bloquean a otras. Necesito una forma de lograr lo mismo en MySQL.

El escenario es que tenemos trabajos de larga ejecución que ocasionalmente crean una transacción anidada que actualiza el campo de progreso. De esta forma, no perderemos la transaccionalidad del trabajo mientras mantenemos informado al usuario sobre el progreso (es decir, el porcentaje completado). La transacción anidada a veces arroja una excepción de tiempo de espera de bloqueo.

Esto es muy extraño, ya que ninguno de los otros trabajos debería escribir, o incluso leer, de la tabla de Trabajo. Revisar el registro de SQL sin procesar confirma esto. Aquí está la sección de transacciones de estado muestran INNODB:

------------ 
TRANSACTIONS 
------------ 
Trx id counter 0 479427 
Purge done for trx's n:o < 0 479425 undo n:o < 0 0 
History list length 19 
LIST OF TRANSACTIONS FOR EACH SESSION: 
---TRANSACTION 0 0, not started, OS thread id 3192 
MySQL thread id 31, query id 17417 localhost 127.0.0.1 root 
show engine innodb status 
---TRANSACTION 0 0, not started, OS thread id 3776 
MySQL thread id 29, query id 13062 localhost 127.0.0.1 root 
---TRANSACTION 0 479190, not started, OS thread id 2540 
MySQL thread id 23, query id 16103 localhost 127.0.0.1 testuser 
---TRANSACTION 0 479422, not started, OS thread id 2536 
MySQL thread id 19, query id 17338 localhost 127.0.0.1 testuser 
---TRANSACTION 0 479194, not started, OS thread id 2528 
MySQL thread id 20, query id 16103 localhost 127.0.0.1 testuser 
---TRANSACTION 0 479189, not started, OS thread id 2776 
MySQL thread id 22, query id 16103 localhost 127.0.0.1 testuser 
---TRANSACTION 0 479426, ACTIVE 3 sec, OS thread id 2544 starting index read 
mysql tables in use 1, locked 1 
LOCK WAIT 2 lock struct(s), heap size 320, 1 row lock(s) 
MySQL thread id 18, query id 17414 localhost 127.0.0.1 testuser Updating 
update Job set progress=0.000482780829770491 where id=28 
------- TRX HAS BEEN WAITING 3 SEC FOR THIS LOCK TO BE GRANTED: 
RECORD LOCKS space id 0 page no 23927 n bits 72 index "PRIMARY" of table "test"."job" trx id 0 479426 lock_mode X locks rec but not gap waiting 
Record lock, heap no 5 PHYSICAL RECORD: n_fields 12; compact format; info bits 0 
0: len 8; hex 000000000000001c; asc   ;; 1: len 6; hex 0000000750bf; asc  P ;; 2: len 7; hex 0000005d4d2aeb; asc ]M* ;; 3: len 8; hex 0000000000000005; asc   ;; 4: len 8; hex 0000000000000004; asc   ;; 5: len 8; hex 0000000000000006; asc   ;; 6: len 1; hex 49; asc I;; 7: len 14; hex 800000000000000002749e0e51a6; asc   t Q ;; 8: len 30; hex 3c6d61703e0a20203c656e7472793e0a202020203c737472696e673e7061; asc <map> <entry>  <string>pa;...(truncated); 9: len 8; hex 80001245d33e7e3c; asc E >~<;; 10: SQL NULL; 11: SQL NULL; 

------------------ 
---TRANSACTION 0 479418, ACTIVE 31 sec, OS thread id 960 
14 lock struct(s), heap size 1024, 8 row lock(s), undo log entries 3 
MySQL thread id 21, query id 17404 localhost 127.0.0.1 testuser 

Parece claro que sólo hay dos transacciones, y que uno de los 14 bloqueos de transacción 479.418 transacción está bloqueando 479426. Me gustaría saber cuál es el consulta ofensiva es. ¿Algunas ideas? Incluso enumerar los 14 bloqueos y las consultas que los causaron sería genial.

Gracias!

Respuesta

0

En una sesión de msql> tratar

12.5.5.31. SHOW PROCESSLIST Sintaxis

MOSTRAR [FULL] PROCESSLIST

SHOW PROCESSLIST muestra los flujos en ejecución. También puede obtener esta información de la tabla INFORMATION_SCHEMA PROCESSLIST o del comando mysqladmin processlist. Si tiene el privilegio PROCESO, puede ver todos los hilos. De lo contrario, solo puede ver sus propios hilos (es decir, los hilos asociados con la cuenta MySQL que está utilizando). Si no utiliza la palabra clave COMPLETA, solo se muestran los primeros 100 caracteres de cada declaración en el campo Información.

+1

Esta afirmación solo muestra lo que se está ejecutando exactamente en el momento en que se ejecuta. Dado que mi proceso de trabajo está ejecutando cientos de sentencias por segundo, los registros de SQL son probablemente más apropiados para solucionar este problema. –

0

Una opción es habilitar el general query log, que registrará todas las instrucciones ejecutadas contra mysql. Solo ten cuidado, no se come todo tu espacio en el disco.

Compara los registros contra los ids en la salida de estado de innodb, y encontrarás al culpable.

+0

Sí ... eso es lo que quise decir con "registro de SQL" en la pregunta. Al hojear este registro no se obtiene ninguna referencia a la tabla de trabajo (ni claves externas en la tabla). Tengo mucha curiosidad por saber por qué hay un tiempo de espera de bloqueo en una actualización de esta tabla dado este escenario. –

+0

Hmm, si fallan, es posible que nunca lleguen allí. Necesitarás tcpdump (no olvides -s 1500 para sacar todo el paquete del cable). –

+0

No estoy muy seguro de lo que quiere decir con esto. Puedo confirmar que la declaración UPDATE en la tabla Job lo hace en MySQL, ya que es la última línea en el archivo de registro. Esto también es respaldado por el volcado de registro anterior que enumera la ACTUALIZACIÓN en la transacción 479426. El problema es que hay un bloqueo existente en la tabla de Trabajo que bloquea la actualización. –

4

Si sus consultas esperan hasta tres segundos, eso las haría fáciles de capturar en el slow-query-log. Otra sugerencia que Xaprb escribe es a use InnoTop. Hay un S.O. post on a similar InnoDB lock issue.

Sin embargo, es posible que desee revisar el código y buscar lugares donde está haciendo una selección de toda la tabla. Por ejemplo, si usted tiene unos elementos de trabajo de mesa y desea seleccionar los que están pendientes, haciendo un

SELECT * FROM queue WHERE status = 'pending' ORDER BY create_date LIMIT 1` 

podría ser activando su condición temp-file-tipo que ocupará toda la tabla si se trata de una transacción. Agregar FOR UPDATE a la selección podría ayudarlo a adquirir mejor el bloqueo. Aparentemente, clustering primary keys can help.

En mi entorno, mi conexión de consulta generará un error en un problema de bloqueo de transacción, por lo que veo errores como: Deadlock found when trying to get lock; try restarting transaction.Es posible que deba verificar las advertencias si su consulta está fallando realmente. (Esto podría no ser de ayuda si no puede cambiar la forma en que la aplicación informa errores de consulta.)

+1

Esta es información muy buena ... ¡gracias! En mi caso específico, ninguna de las consultas en la transacción externa toma mucho tiempo (0.1 segundos es la más larga), y - curiosamente - no hace referencia alguna a la tabla de Trabajo, donde ocurre el tiempo de espera de bloqueo. Nuestra solución implica Hibernate, por lo que ninguna de las consultas es particularmente complicada (es decir, no para FORD UPDATE). Finalmente, tengo un error específico: "Se ha excedido el tiempo de espera de espera de bloqueo; intente reiniciar la transacción". Sin embargo, dado que el error ocurre en una transacción anidada, ninguna cantidad de reinicio de transacción ayuda. –

Cuestiones relacionadas