2011-06-07 14 views
16

No está del todo claro por MySQL documentation si el motor InnoDB implementa cierto aislamiento serializable o snapshot isolation, que a menudo confusamente llamado "serializable" también. ¿Cuál es?¿MySQL/InnoDB implementa un verdadero aislamiento serializable?

Si MySQL InnoDB no lo hace, ¿hay algún RDBMS completamente gratuito y de calidad de producción que lo haga?

donde "cierto aislamiento serializable" significa la ausencia de anomalías no sólo lectura según la norma SQL, sino también la inclinación de escritura anomalía, explicó con más detalle here.

+2

Me encanta escuchar esto. Necesitamos la función X, pero definitivamente no queremos pagarla. – Kibbee

+6

Me alegra haberte hecho un poco más feliz, @Kibbee. –

+0

Si define lo que quiere decir ser un "verdadero aislamiento serializable", tal vez la gente pueda aclarar esto un poco. – Kibbee

Respuesta

9

¿Hay algún RDBMS completamente gratuito y de calidad de producción que lo haga?

Postgres tiene soporte para el verdadero aislamiento serializable starting with version 9.1. Ciertamente califica como "completamente libre" y "de calidad de producción".

+1

Esto ya no es cierto? Ver comentarios a la respuesta anterior de regileros - MySQL parece haber solucionado el problema en 5.5. –

+0

@PiotrBlasiak Es posible que el ejemplo específico sea fijo, pero a menos que MySQL anuncie el aislamiento verdadero, espero que solo implemente la variante menor. Sin embargo, eliminaré mi reclamo sobre MySQL ya que ahora no tiene ninguna fuente. –

-5

No creo que MySQL implemente el aislamiento serializable, que, según tengo entendido, requeriría la capacidad de deshacer, que definitivamente no es compatible. Para obtener más información, lea here.

+0

Justo en la parte superior de ese artículo, indica que está desactualizado y no representa los últimos datos con respecto a MySQL. Si bien las tablas MyISAM no admiten reversiones, o transacciones en absoluto, InnoDB admite transacciones con reversión. – Kibbee

+0

Sé con certeza que MySQL + InnoDB admite transacciones; la pregunta es solo sobre qué significan exactamente sus transacciones "serializables". –

+0

MySQL de hecho admite transacciones. El controlador de la tabla MyISAM no admite * el bloqueo de nivel de fila *, pero InnoDB lo soluciona también. – Zds

-2

Leyendo más en el enlace you provided, dice que el uso del modo "lectura repetible" (el valor predeterminado para innodb) elimina las anomalías de lectura, como usted mencionó como uno de sus requisitos. Además, al leer su segundo enlace, parece que el manejo de las anomalías de escritura se traslada al usuario final. En el artículo, mencionan Oracle's Select for Update, que MySQL also supports. No estoy seguro de si esto cumple con sus requisitos, pero debería ayudarlo un poco.

+0

Sí ... aunque el segundo enlace explica qué es * el aislamiento de instantáneas *, no si MySQL tiene aislamiento de instantáneas o aislamiento verdaderamente serializable, por lo que todavía no estoy seguro. –

10

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.

+2

No lo entiendo ¿Todavía funciona de esta manera en MySQL 5.5? –

+0

@Seun Osewa: así es, lo intenté también con 5.5 y parece que la tabla está bloqueada, quizás se haya eliminado la 'optimización de índice' incorrecta. Ya no puedo obtener un ejemplo de serialización incorrecto. – regilero

+0

Obtengo algunos votos abajo aquí, eso es divertido, no hay comentarios, solo votos abajo ... tal vez un desarrollador de MySQL. – regilero

1

¿Estás seguro de que estás utilizando transacciones "serializables"? Para estar seguro, debe usar "SET session TRANSACTION ISOLATION LEVEL SERIALIZABLE"; para que toda la sesión se pueda serializar y no solo la próxima transacción.

estoy probando con 05.05.29 en OSX

y cuando intento insertar (3,30) en T1, después de la creación del índice en clase, transacción espera y aborta tras el tiempo límite de espera de bloqueo. (T2 todavía está en progreso)

Cuestiones relacionadas