Las consultas de ACTUALIZACIÓN en sus dos preguntas anteriores ( Pregunta1 , Pregunta2 ) están golpeando la tabla 'personas' por PRIMARY KEY con bloqueo de nivel de fila. Esto es lo que dije en la Pregunta 1 el 6 de junio de 2011 10:03 a.m.
Todas las transacciones atraviesan la clave PRIMARIA. Dado que PRIMARY es un índice agrupado en InnoDB, la clave PRIMARY y la fila en sí están juntas. Por lo tanto, atravesar una fila y la CLAVE PRIMARIA son lo mismo. Por lo tanto, cualquier bloqueo de índice en PRIMARY KEY también es un bloqueo de nivel de fila.
Todavía no se ha considerado otra cosa que pueda atribuir lentitud a los índices: el uso de índices NO ÚNICOS en InnoDB. Cada búsqueda indexada en InnoDB que utiliza índices no únicos también tiene el ID de fila de cada fila asociada a la clave no única. El rowID básicamente emana del índice agrupado . La actualización de índices no únicos DEBE SIEMPRE interactuar con el índice agrupado INCLUSO SI LA TABLA NO TIENE UNA CLAVE PRIMARIA.
Otra cosa a tener en cuenta es el proceso de gestión de nodos BTREE en un índice. A veces, requiere la división de la página de los nodos. Todas las entradas en el nodo BTREE de índices no únicos contienen campos no únicos MÁS el ID de fila dentro del índice agrupado. Para mitigar adecuadamente la división de tales páginas BTREE sin alterar la integridad de los datos, la fila asociada con el ID de fila debe experimentar un bloqueo de nivel de fila internamente.
Si la tabla de 'personas' tiene muchos índices no únicos, prepárese para tener una gran cantidad de páginas de índice en el espacio de tablas, así como tener pequeños bloqueos de filas que se le acerquen de vez en cuando.
Hay otro factor que no es tan obvio: la población clave
A veces, cuando se llena un índice, los valores clave que componen los índices pueden desviarse con el tiempo y hacer que MySQL Query Optimizer cambie de búsquedas con clave a escaneos de índice y finalmente a escaneos de tabla completa. Eso no puede controlarlo a menos que rediseñe la tabla con nuevos índices para compensar la desigualdad de las teclas. Proporcione la estructura de la tabla para la tabla 'personas', el recuento de la tabla 'personas' y la salida de los índices de la tabla 'personas' .
Incluso si las consultas usan solo la CLAVE PRIMARIA, la desigualdad de las claves en los índices no únicos todavía necesita el equilibrio BTREE y la división de la página para que ocurra. Tal gestión de BTREE producirá una notable desaceleración debido a bloqueos intermitentes de nivel de fila que no tenía la intención de suceder.
ACTUALIZACIÓN 2011-06-14 22:19
Consultas de la pregunta 1
UPDATE people SET company_id = 1610, name = '<name>', password = '<hash>',
temp_password = NULL, reset_password_hash = NULL, email = '<redacted>@yahoo.com',
phone = NULL, mobile = '<phone>', iphone_device_id = 'android:<id>-<id>',
iphone_device_time = '2011-06-06 05:35:09', last_checkin = '2011-06-06 05:24:42',
location_lat = <lat>, location_long = -<lng>, gps_strength = 3296,
picture_blob_id = 1190,
authority = 1, active = 1, date_created = '2011-04-13 20:21:20',
last_login = '2011-06-06 05:35:09', panic_mode = 0,
battery_level = NULL, battery_state = NULL WHERE people_id = 3125
UPDATE people SET company_id = 1610, name = '<name>', password = '<hash>',
temp_password = NULL, reset_password_hash = NULL, email = '<redacted>@yahoo.com',
phone = NULL, mobile = '<phone>', iphone_device_id = 'android:<id>-<id>-<id>-<id>',
iphone_device_time = '2011-06-06 05:24:42', last_checkin = '2011-06-06 05:35:07',
location_lat = <lat>, location_long = -<lng>, gps_strength = 3296,
picture_blob_id = 1190,
authority = 1, active = 1, date_created = '2011-04-13 20:21:20',
last_login = '2011-06-06 05:35:09', panic_mode = 0,
battery_level = NULL, battery_state = NULL WHERE people_id = 3125
Imagen de la secuencia en eventos
- Encuentra la fila por PRIMARY KEY
- Bloquee la fila y el índice agrupado
- Crear datos MVCC para todas las columnas que se actualizan
- Se indexan cuatro columnas (email, company_id, iphone_device_id, picture_blob_id)
- Cada índice requiere gestión BTREE
- Dentro del mismo espacio de transacción, los pasos 1-5 intentan repetirse en la misma fila, actualizando las mismas columnas (enviar el mismo correo electrónico en ambas consultas, company_id lo mismo en ambas consultas, picture_blob_id lo mismo en ambas consultas, iphone_device_id diferente)
Consultas de la pregunta 2
UPDATE people SET iphone_device_id=NULL
WHERE iphone_device_id='iphone:<device_id_blah>' AND people_id<>666;
UPDATE people SET company_id = 444, name = 'Dad', password = '<pass>',
temp_password = NULL, reset_password_hash = NULL, email = '<redacted>@gmail.com',
phone = NULL, mobile = NULL, iphone_device_id = 'iphone:<device_id_blah>',
iphone_device_time = '2011-06-06 19:12:29', last_checkin = '2011-06-07 02:49:47',
location_lat = <lat>, location_long = <lng>, gps_strength = 66,
picture_blob_id = 1661,
authority = 1, active = 1, date_created = '2011-03-20 19:18:34',
last_login = '2011-06-07 11:15:01', panic_mode = 0, battery_level = 0.55,
battery_state = 'unplugged' WHERE people_id = 666;
Estas dos consultas son aún más confusas porque la primera consulta está actualizando todo excepto people_id 666. Cientos de filas se están bloqueando dolorosamente con solo la primera consulta. La segunda consulta está actualizando people_id 666 ejecutando la secuencia de 5 eventos. La primera consulta ejecuta esas mismas 5 secuencias de eventos en cada fila involucrada, excepto people_id 666, pero el índice para iphone_device_id está en un curso de intersección con dos consultas diferentes. Alguien tiene que bloquear las páginas de BTREE por orden de llegada.
Frente a estos dos pares de consultas en un curso de colisión para posiblemente bloquear las mismas páginas BTREE dentro de un índice, puede ser una experiencia desgarradora para InnoDB o cualquier RDBMS compatible con ACID. Por lo tanto, una ralentización del índice es el destino de estos pares de consultas a menos que pueda garantizar que las consultas se ejecuten con AUTOCOMMIT = 1 o permitiendo lecturas sucias (aunque colisiones como estas hacen que READ-COMPROMISO y READ-NO COMPROMISO sea una pesadilla para MVCC).
ACTUALIZACIÓN 2011-06-15 10:29
@RedBlueThing: en las consultas de la pregunta 2, la primera consulta es una consulta de rango, por lo que se están logrando muchos bloqueos de fila. Observe también que ambas consultas están tratando de bloquear el mismo espacio id 0 página no 4611 n bits 152 se está bloqueando en la PRIMARY KEY, también conocido como índice agrupado.
Para asegurarse de que su aplicación, como mínimo, se ejecute según la serie de eventos que espera, hay dos opciones diferentes que puede probar:
Opción 1) Convertir esta tabla a MyISAM (al menos en un servidor de desarrollo). Cada ACTUALIZACIÓN, INSERTAR y ELIMINAR impondrá un bloqueo de tabla completo por orden de llegada.
Opción 2) Intente usar el nivel de aislamiento SERIALIZABLE . Eso bloqueará todas las filas previstas en el modo COMPARTIDO.
La secuencia de eventos que espera se interrumpirá o tendrá éxito utilizando estas dos opciones alternativas. Si ambas opciones fallan, deberá revisar su aplicación y priorizar el orden de ejecución de sus consultas. Una vez que establezca esa prioridad, simplemente puede deshacer estas opciones (para la opción 1, regrese a InnoDB, para la opción 2, regrese al nivel de aislamiento predeterminado [deje de usar SERIALIZABLE]).