2011-07-14 18 views
9

Servidor MySQL versión 5.1.41 con el complemento InnoDB habilitado. Tengo las siguientes tres tablas para facturas: facturas, componentes de factura y gastos de factura. Las facturas de tabla tienen la clave primaria invoice_id. Tanto invoice_components como invoice_expenses están vinculados a las facturas de la tabla con invoice_id como una foreign_key no única (cada factura puede tener más de un componente y más de un gasto). Ambas tablas tienen un índice BTREE para esta clave externa.InnoDB SELECT ... PARA la instrucción UPDATE que bloquea todas las filas en una tabla

que tienen las siguientes operaciones:

de transacción 1

START TRANSACTION; 
SELECT * FROM invoices WHERE invoice_id = 18 FOR UPDATE; 
SELECT * FROM invoice_components WHERE invoice = 18 FOR UPDATE; 
SELECT * FROM invoice_expenses WHERE invoice = 18 FOR UPDATE; 

Todo funciona bien para la primera transacción y las filas se seleccionan y se bloquea.

transacción 2

START TRANSACTION; 
SELECT * FROM invoices WHERE invoice_id = 19 FOR UPDATE; 
SELECT * FROM invoice_components WHERE invoice = 19 FOR UPDATE; 
SELECT * FROM invoice_expenses WHERE invoice = 19 FOR UPDATE; 

La segunda transacción vuelve ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction para la tercera consulta.

Lo mismo ocurre cuando trato de SELECCIONAR ... PARA ACTUALIZAR otras facturas y sus componentes y gastos. Parece que la primera transacción ha bloqueado todas las filas en la tabla invoice_expenses. ¿Alguna idea de por qué está pasando esto?

Otros detalles

Transacción 2 comienza después de la tercera consulta de transacción 1. No hay otros usuarios, las conexiones o las transacciones en el servidor.

El problema se produce en el nivel de aislamiento de transacción REPEATABLE READ predeterminado. Se soluciona al cambiar al nivel LECTURA COMPROMETIDA. Esta es una solución, pero aún no explica por qué el problema está ocurriendo con fact_expenses y no con fact_components.

+4

¿Estás seguro de que todos los registros están bloqueados? InnoDB puede bloquear los registros del vecindario (cuando se bloquean 18 - 17 y 19 también), pero no debe bloquear los registros que están muy lejos en el btree - así que intente esto con una mayor distancia en los identificadores. Además, ¿cuál es su nivel de aislamiento? –

+0

@Darhazer. Gracias. Cambiar el nivel de aislamiento a READ COMMITTED resolvió el problema. ¿Puedes explicar lo que estaba pasando? ¿El espaciado MySQL estaba bloqueando mi tabla invoice_expenses? ¿Por qué no sucedió lo mismo con invoice_components? De cualquier manera, si publica una respuesta lo aceptaré. –

+0

No tengo respuesta por qué esto está sucediendo en READATABLE READ, así que preferiría ponerle una recompensa a la pregunta, que publicar una respuesta incompleta. ¿Esas son las únicas consultas que se ejecutan en las transacciones? ¿Se inicia la segunda transacción después de realizar la tercera consulta en la primera transacción, o son concurrentes? Agregaré una recompensa después de los 2 días requeridos por SO –

Respuesta

-2

Usted está utilizando una transacción; autocommit no deshabilita las transacciones, solo las hace confirmar automáticamente al final de las declaraciones que no tienen un start transaction explícito en ellas.

Lo que está sucediendo es que algún otro hilo mantiene un bloqueo de registro en algún registro (está actualizando cada registro en la tabla) durante demasiado tiempo, y se está agotando el tiempo de espera de su hilo.

Puede ver más detalles del evento emitiendo un "ESTADO DEL INNOVADOR DEL MOTOR" después del evento. Lo ideal sería hacer esto en una máquina de prueba silenciosa.

+1

Lo siento, Rush, o no leíste mi pregunta en detalle o no la entendiste muy bien. Mantengo la primera transacción abierta a propósito para probar la concurrencia. El problema es que está bloqueando filas que no está seleccionando en la tabla facturas_expensas. Esto está en un servidor de desarrollo por lo que no hay otros usuarios, conexiones o transacciones. Ya está usando SHOW ENGINE INNODB STATUS. –

9

Sospecho que tiene que ver con cerraduras brecha y bloqueos de próxima clave y las diferencias en el comportamiento de REPETIBLE LEER:

Los extractos son de documentación de MySQL: SET TRANSACTION syntax

Para las lecturas de bloqueo (SELECCIONAR con FOR UPDATE o LOCK IN SHARE MODE), las sentencias UPDATE y DELETE, el bloqueo depende de si la instrucción usa un índice único con un condición de búsqueda única o una condición de búsqueda de rango. Para un índice único con una condición de búsqueda única, InnoDB bloquea solo el registro de índice encontrado, no el espacio existente.Para otras condiciones de búsqueda, InnoDB bloquea el rango de índice escaneado, usando bloqueos de espacio o bloqueos de clave siguiente (espacio más registro de índice) para bloquear las inserciones de otras sesiones en los espacios cubiertos por el rango.

y LEER COMPROMETIDOS:

Nota: En MySQL 5.1, si el nivel de aislamiento READ COMMITTED se utiliza o se activa la variable de sistema innodb_locks_unsafe_for_binlog, no hay ningún hueco InnoDB bloqueo a excepción de verificación de restricción de clave externa y verificación de clave duplicada. Además, bloqueos de registro para filas no coincidentes se liberan después de que MySQL haya evaluado la condición WHERE.

Quizás OP nos puede decir el estado de la variable innodb_locks_unsafe_for_binlog system y si se produce el mismo bloqueo cuando se cambia la configuración de esta variable.

Además, si misma bloqueo ocurre con las identificaciones no secuenciales, como 18 y 20, o 18 y 99

+0

Mi innodb_locks_unsafe_for_binlog está desactivado. Tengo los mismos resultados cuando bloqueo las filas para la identificación 18 y trato de seleccionar las filas de actualización para la identificación 21. No hay una identificación 20. –

+0

@ Miloš: ¿Y si configura 'innodb_locks_unsafe_for_binlog' en ON? ¿Todavía sucede? –

+0

No podemos decir todavía si esto está causando el problema, pero su respuesta es útil para mí, y es la única que proporciona algunas ideas, por lo que le otorgo la recompensa. Espero que OP continúe probando y encontraremos la causa raíz. –

0

"Para el índice registra los encuentros de búsqueda, SELECT ... FROM ... DE ACTUALIZACIÓN bloques que otras sesiones haciendo SELECCIONAR ... DESDE ... BLOQUEAR EN MODO COMPARTIR o desde leer en ciertos niveles de aislamiento de transacción. Las lecturas consistentes ignorarán cualquier bloqueo establecido en los registros que existen en la vista de lectura "

¿Cuáles son esos ciertos bloqueos que pueden se aplica con seleccionar para la actualización para que otras sesiones no puedan leer el registro bloqueado?

Cuestiones relacionadas