Bienvenidos sean a este post, hoy hablaremos sobre los locks o bloqueos de este motor de almacenamiento.
Pero que es un bloqueo?, podemos definirlo como:
Un bloqueo es una estructura de datos que es adquirida por un usuario y asociado a un recurso.
El Tinchicus
Mientras el bloqueo este activo los otros usuarios no seran capaces de modificar al recurso, aunque tambien depende del tipo de bloqueo tampoco podran leer del mismo, lo mas usual es enlistar las operaciones concurrentes para que no colisionen entre si, para poder entender como trabajan los bloqueos se deben entender como trabajan las transacciones, es decir cuando una transaccion necesita acceder a una linea que esta bloqueada es pasada a retenido (hold) hasta que se libere dicho bloqueo, pero como todo esta espera tiene un limite y una vez superado se produce un error y se devuelve el mismo en pantalla, un ejemplo seria el siguiente:
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
Los modos de bloqueo
El motor de almacenamiento tiene dos modos de bloqueo:
- shared, evita que otra instruccion escriba pero permite leer
- exclusive, esta evita inclusive la lectura
Por lo tanto el primer modo es utilizado antes de leer una linea y el segundo es utilizado antes de escribir una linea, pero antes que una transaccion pueda adquirir algunos de los dos bloqueos necesita adquirir una intencion de bloqueo shared o bloqueo exclusive, es decir que una intencion de bloqueo indica que una transaccion esta esperando adquirir alguno de estos bloqueos (shared o exclusive) y evita que dos conexiones adquieran un bloque en las mismas lineas, por esto un bloqueo en un registro solo puede ser adquirido si un bloqueo incompatible no esta envuelto en el mismo registro, por lo tanto si un bloqueo existe la conexion es retenida.
Tipos de bloqueo
El motor soporta dos tipos de bloqueo:
- Nivel tabla
- Nivel registro
El primero bloquea una tabla completa, tiene la particularidad de poder ser adquirida explicitamente mediante LOCK TABLES, aunque no es una practica recomendable y el motor usualmente lo tiene desactivado de manera predeterminada, el segundo tipo bloquea uno o mas registros, a su vez InnoDB tiene varios sub-tipos para este:
- Bloqueo de registro, record lock, bloquea al indice de un registro, si no existe trabaja sobre todos los registros del indice agrupado
- Bloqueo de proxima clave, next-key lock, en este caso involucra al indice de un registro y todos los registro que le preceden, este ayuda a prevenir que otras conexiones inserten o modifiquen los registros que ya han sido accedidos por la transaccion actual
- Bloqueo de espacio, gap lock, este bloqueo es sobre un conjunto de registros, este conjunto puede ser desde un solo record hasta multiples e inclusive vacio, no es utilizado para busquedas de una sola linea en un indice UNIQUE, salvo que se compongan de multiples columnas
Un caso particular de bloqueo de espacio es el bloqueo de espacio de insercion, es adquirido antes de la insercion de una nueva linea, si otra conexion intenta insertar una linea con los mismos valores de indices esta se retendra hasta que transaccion actual se ejecute o vuelva atras los cambios, por ultimo estos tipos de bloque no son usados por el nivel de aislamiento READ COMMITED.
Bloqueos de diagnosticos
Si bien los bloqueos se usan para mantener una consistencia de datos tambien pueden generar problemas de performance, dado que pueden generar que muchas sesiones esperen generando demoras en las aplicaciones, si esto ocurre muy seguido debemos averiguar el porque y solucionarlo, una de las mejores formas de hacerlo es por medio del comando SHOW ENGINE INNODB STATUS, ya que es la forma mas rapida y humanamente legible para obtener informacion de los bloqueos, su salida es larga pero entendible, amigable con la expresiones regulares, y dividida en secciones utiles, la seccion de los bloqueos es TRANSACCIONES, veamos un ejemplo:
------------
TRANSACTIONS
------------
Trx id counter 14488
Purge done for trx's n:o < 14477 undo n:o < 0 state: running but idle
History list length 230
LIST OF TRANSACTIONS FOR EACH SESSION:
…
---TRANSACTION 14509, ACTIVE 3 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 376, 1 row lock(s), undo log entries 1
MySQL thread id 5, OS thread handle 0x7f5d48554700, query id 161 localhost root update
INSERT INTO t VALUES (1)
------- TRX HAS BEEN WAITING 3 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 48 page no 4 n bits 72 index `a` of table `test`.`t` trx id 14509 lock mode S waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 4; hex 80000001; asc ;;
1: len 6; hex 000000000601; asc ;;
------------------
---TRANSACTION 14486, ACTIVE 9 sec
2 lock struct(s), heap size 376, 1 row lock(s), undo log entries 1
MySQL thread id 4, OS thread handle 0x7f5d4859d700, query id 154 localhost root cleaning up
En este ejemplo podemos ver como cada transaccion tiene un ID de mysql, para saber cual es la accion correspondiente podemos usar SHOW PROCESSLIST y verlo en base a su ID, en formato hexadecimal vemos al thread del sistema, este se puede convertir en decimal por medio de UNHEX, por ultimo se puede obtener mas informacion simplemente haciendo un query sobre la tabla INNODB_LOCKS de la base information_schema, antes de ver un ejemplo hablemos de sus columnas:
- lock_id, este almacena el id, ahora en formato cadena pero cambiara en el futuro
- lock_trx_id, este almacena el id de la transaccion
- lock_mode, almacena el modo del bloqueo
- lock_type, almacena el tipo de bloqueo
- lock_table, almacena la tabla donde se realizo el bloqueo
- lock_index, almacena el nombre del indice cuyo registro esta bloqueado, aplica solo a los bloqueos de registros
- lock_space, almacena el nombre del espacio de tabla envuelto en el bloqueo, aplica solo a los bloqueos de registros
- lock_page, almacena el numero de pagina, aplica solo a los bloqueos de registros
- lock_rec, almacena el numero de registro dentro de la pagina, aplica solo a los bloqueos de registros
- lock_data, almacena el valor del indice agrupado del registro bloqueado, aplica solo a los bloqueos de registros
El lock_mode puede contener estos valores:
- S (shared)
- X (exclusive)
- IS (intention shared)
- IX (intention exclusive)
- S_GAP (shared para gap locks)
- X_GAP (exclusive para gap locks)
- IS_GAP (intention shared para gap locks)
- IX_GAP (intention exclusive para gap locks)
- AUTO_INC, para bloqueos auto incrementables
Tambien podemos usar a la tabla INNODB_LOCK_WAITS para saber cuales son las transacciones que estan esperando por un bloqueo y cuales son las transacciones que estan reteniendo estos bloqueos los cuales no les permiten continuar, las columnas son:
- requesting_trx_id, almacena el id de la transaccion esperando
- requested_lock_id, almacena el id del bloqueo solicitado
- blocking_trx_id, almacena el id de la transaccion bloqueadora
- blocking_lock_id, almacena el id de la bloqueo que bloquea a la transaccion solicitante
Por ultimo esta la tabla INNODB_TRX que almacena informacion sobre las actividades de las transacciones, tambien observen que la informacion manipulada por esta base, information_schema, no tiene nada que ver con lo devuelto por LOCK TABLES dado que este ultimo es manipulado directamente por mariadb.
En resumen, hoy hemos visto a los bloqueos de InnoDB, como son, para que se usan, como nos ayudan a tener una mejora consistencia de datos, como pueden acarrear problemas de performances, los modos que poseen, los tipos, como se pueden obtener algunos diagnosticos y algunas tablas donde se almacena dicha informacion, espero les haya sido util sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.


Donación
Es para mantenimento del sitio, gracias!
$1.50
