Aquí están mis notas de trabajar con el soporte de MySQL en un problema de bloqueo extraño reciente (versión 5.1.37):
Se bloquearán todas las filas y entradas de índice recorridas para llegar a las filas que se están modificando. Está cubierto en:
http://dev.mysql.com/doc /refman/5.1/en/innodb-locks-set.html
"Una lectura de bloqueo, una ACTUALIZACIÓN o una ELIMINACIÓN generalmente establecen bloqueos de registro en cada registro de índice que se escanea en el procesamiento de la declaración SQL. No importa si hay condiciones WHERE en la declaración que excluirían la fila. InnoDB lo hace no recuerda la condición DONDE exacta, pero solo sabe qué rangos de índices se escanearon... Si no tiene índices adecuados para su declaración y MySQL debe escanear toda la tabla para procesar la declaración, cada fila de la tabla se bloquea, lo que en Turn bloquea todas las inserciones de otros usuarios en la mesa".
Está. Una solución alternativa que suele ser útil es hacer lo siguiente:
ACTUALIZAR cualquier tabla establecer lo que sea en algo donde la clave principal esté (seleccione la clave principal de cualquier tabla donde las restricciones se ordenen por clave principal);
La selección interna no necesita tomar bloqueos y la actualización tendrá menos trabajo que hacer para la actualización. La cláusula order by garantiza que la actualización se realice en orden de clave principal para que coincida con el orden físico de InnoDB, la forma más rápida de hacerlo.
Cuando se trata de un gran número de filas, como en su caso, puede ser mejor almacenar el resultado seleccionado en una tabla temporal con una columna de bandera agregada. Luego, seleccione de la tabla temporal donde la bandera no está configurada para obtener cada lote. Ejecute actualizaciones con un límite de, por ejemplo, 1000 o 10000 y configure el indicador para el lote después de la actualización. Los límites mantendrán la cantidad de bloqueo en un nivel tolerable, mientras que el trabajo de selección solo deberá realizarse una vez. Comprométase después de cada lote para liberar los bloqueos.
También puede acelerar este trabajo haciendo una suma seleccionada de una columna no indexada antes de realizar cada lote de actualizaciones. Esto cargará las páginas de datos en el grupo de búfer sin realizar bloqueos. Luego, el bloqueo durará menos tiempo porque no habrá lecturas de disco.
Esto no siempre es práctico, pero cuando lo es puede ser muy útil. Si no puede hacerlo en lotes, al menos puede intentar seleccionar primero para precargar los datos, si es lo suficientemente pequeño como para caber en el grupo de búfer.
Si es posible, utilice el modo de aislamiento de transacciones de LECTURA COMPROMETIDA. Ver:
http://dev.mysql.com/doc/refman /5.1/es/set-transaction.html
Para obtener ese bloqueo reducido, se requiere el uso de registros binarios basados en filas (en lugar del registro binario basado en sentencias predeterminado).
Dos problemas conocidos:
-
Las subconsultas pueden estar optimizadas menos que idealmente a veces. En este caso, se trataba de una subconsulta dependiente no deseada:la sugerencia que hice de usar una subconsulta resultó inútil en comparación con la alternativa en este caso debido a eso.
-
Las eliminaciones y las actualizaciones no tienen el mismo rango de planes de consulta que las instrucciones de selección, por lo que a veces es difícil optimizarlas correctamente sin medir los resultados para determinar exactamente lo que están haciendo.
Ambos están mejorando gradualmente. Este error es un ejemplo en el que acabamos de mejorar las optimizaciones disponibles para una actualización, aunque los cambios son significativos y aún se está sometiendo a control de calidad para asegurarnos de que no tenga grandes efectos adversos:
http://bugs.mysql.com/bug.php?id=36569