ACTUALIZACIÓN:
Véanse los comentarios, esto parece ser fija en MySQL 5.5, con estos ejemplos que aún tenemos un bloqueo de tabla y el índice de bloqueo de próxima clave no puede ser engañado, que yo sepa.
original:
encontrado tu pregunta ayer y me preguntaba sobre el modelo seriability MVCC de InnoDB también.
Así que hice algunas pruebas . MySQL 5.1.37. Una buena prueba para el problema de serializabilidad es la proporcionada en postgrESQL 9.0 MVCC documentation, en este capítulo Aislamiento serializable versus Serializabilidad verdadera podemos ver el límite del modelo MVCC en serializabilidad si no se realiza el bloqueo de predicado.
Así que vamos a probarlo en MySQL:
CREATE TABLE t1 (
class integer,
value integer
) ENGINE=InnoDB;
INSERT INTO t1 (`class`,`value`) VALUES
(1,10),
(1,20),
(2,100),
(2,200);
Ahora vamos a abrir dos conexiones diferentes a tener dos transacciones paralelas (T1 y T2):
T1:
SET TRANSACTIOn ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT SUM(value) FROM t1 WHERE class = 1;
El resultado es 30.
T2:
SET TRANSACTIOn ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT SUM(value) FROM t1 WHERE class = 2;
El resultado es 300.
Ahora viene el problema serializabilidad.Si T1 inserta una fila, la selección de T2 no es válida (aquí T2 hace lo mismo).
T1:
INSERT INTO t1 (`class`,`value`) VALUES (2,30);
==> espera (un bloqueo está en su lugar)
T2:
INSERT INTO t1 (`class`,`value`) VALUES (1,300);
==> ERROR 1213 (40001): Se encontró un punto muerto cuando se intentaba obtener el bloqueo; intente reiniciar la transacción
T1 ahora tiene éxito en su inserción, t2 tenía un ROLLBACK, buena serializabilidad.
Esto fallaría en PostgreSQL 9.0 (las cosas están cambiando en 9.1, pero es otro problema). De hecho, solo uno de las transacciones puede realizar una inserción en la tabla. Incluso si tratamos de insertar en class=3
con.
INSERT INTO t1 (`class`,`value`) VALUES (3,30);
Veríamos un bloqueo de espera y bloqueos en caso de problemas. Parece que tenemos un bloqueo de predicado en MySQL ... Pero de hecho es una implementación next-key locking en InnoDB.
Innodb realiza bloqueos de fila con algunos huecos bloqueados también en los índices. Aquí no tenemos índices en la tabla, parece que MySQL decidió bloquear la tabla.
Intentemos probar el siguiente bloqueo de teclas para ver si esto impone la serialización. Primero reinicie la transacción en ejecución (T1). Luego crea un índice.
CREATE index t1class ON t1 (class);
Ahora vuelva a hacer la prueba. Éxito, la serialización todavía se aplica. Buenas noticias.
Pero con el índice en su lugar creo que el bloqueo de la próxima tecla y los bloqueos de fila se realizan en el índice. Esto significa que deberíamos poder realizar una inserción si no afecta una transacción paralela ... y aquí viene el gran problema.
T1:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT SUM(value) FROM t1 WHERE class = 1;
resultado es 30.
T2:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT SUM(value) FROM t1 WHERE class = 2;
resultado es 300.
Aquí vamos a hacer una inserción no relacionada en T1, ahora que tenemos un índice este tendrá éxito:
T1:
INSERT INTO t1 (`class`,`value`) VALUES (3,30);
Tanto puede realizar la inserción (aquí hice solo uno), eso es normal. El bloqueo predictivo no se aplica, no se han realizado consultas SELECT en class=3
. Parece que el bloqueo de la siguiente clave funciona mejor si le damos buenos índices (sin bloqueo de tabla en las inserciones).
Ahora intenta insertar en la siguiente tecla de bloqueo, en una selección fila coincidente de T2 (clase = 2):
T1:
INSERT INTO t1 (`class`,`value`) VALUES (2,30);
Ouch. Es tiene éxito!
T2:
INSERT INTO t1 (`class`,`value`) VALUES (1,300);
==> espera. Todavía hay una cerradura allí. Ojalá.
T1:
COMMIT;
T2: (donde la cerradura ha pasado, se hace el inserto)
SELECT SUM(value) FROM t1 WHERE class = 2;
COMMIT;
Todavía tiene 300 aquí. Parece que la serializabilidad se ha ido.
select * from t1;
+-------+-------+
| class | value |
+-------+-------+
| 1 | 10 |
| 1 | 20 |
| 2 | 100 |
| 2 | 200 |
| 3 | 30 | <-- test
| 2 | 30 | <-- from trans1
| 1 | 300 | <-- from trans2 ERROR!
+-------+-------+
Resultado: Al insertar una nueva fila sin relación antes de insertar una fila impactar una consulta de movimientos paralelos que hemos suplantado la siguiente tecla mecanismo de bloqueo. O al menos esto es lo que entiendo de mis pruebas. Entonces, yo diría que no confíe en el motor para verdadera serializabilidad. Cuando tenga agregados funciones en una transacción lo mejor es manualmente bloquear la tabla, transformar su problema de serializabilidad en una situación real de un solo hombre, sin sorpresas! Otros problemas de serializabilidad en los ejemplos son las verificaciones de restricciones (verifique que la cantidad sigue siendo positiva después de su operación), también tiene bloqueos en estos casos.
Me encanta escuchar esto. Necesitamos la función X, pero definitivamente no queremos pagarla. – Kibbee
Me alegra haberte hecho un poco más feliz, @Kibbee. –
Si define lo que quiere decir ser un "verdadero aislamiento serializable", tal vez la gente pueda aclarar esto un poco. – Kibbee