locked
Diferencias entre niveles de aislamiento en transacciones... ISOLATION LEVEL RRS feed

  • Pregunta

  • Hola como están todos…

    Cuál es la diferencia en los siguientes niveles de Aislamiento…

    -        READ COMMITTED

    -        READ UNCOMMITTED

    -        REPETEABLE READ

    -        SERIALIZABLE

     

    Según los libros en línea “http://msdn.microsoft.com/en-us/library/aa259216(SQL.80).aspx”Definen

    READ COMMITTED: Especifica que los bloqueos compartidos se mantienen mientras que los datos se lee para evitar lecturas sucias, pero los datos se pueden cambiar antes de que finalice la transacción.

    READ UNCOMMITTED:  Implementa lecturas sucias, o el aislamiento de bloqueo de nivel 0, lo que significa que no se emiten bloqueos. Cuando se establece esta opción, es posible leer datos sucios o no comprometidos, los valores en los datos se pueden cambiar y las filas pueden aparecer o desaparecer en el conjunto de datos antes de que finalice la transacción.

    REPEATABLE READ: Los bloqueos se coloca en todos los datos que se utiliza en una consulta, evitando que otros usuarios puedan actualizar los datos, pero las nuevas filas fantasma se puede insertar en el conjunto de datos por otro usuario y se incluyen en adelante se lee en la transacción actual.

    SERIALIZABLE: Coloca un bloqueo de rango en el conjunto de datos, impidiendo que otros usuarios actualizar o insertar filas en el conjunto de datos hasta que la transacción se ha completado. Esta es la más restrictiva de los cuatro niveles de aislamiento.

     

    Yo entiendo lo siguiente.

    COMMITTED: puedo realizar INSERT pero no puedo realizar UPDATE, DELETE o SELECT  mientras se realiza la transaccion. “Supongo que el UPDATE Y DELETE no entran en la parte de los datos que se pueden cambiar ya que para poder ejecutar estos obligatoriamente tienen que hacerse una lectura de los datos…

    UNCOMMITTED: puedo realizar INSERT, UPDATE, DELETE o SELECT  mientras se realiza la transaccion.

    REPEATABLE READ: No puedo realizar ni UPDATE, DELETE y cuando hago INSERT estos van a colocar antes de los datos que se puedan ingresar en la transaccion.

    SERIALIZABLE: Bloquea todo y practicamente no puedo hacer nada….

    Ahora si voy al punto de mis dudas…

    Esto solo se aplica cuando realizo en las Transacciones consultas “SELECT”?

    Estoy tratando de hacer lo siguiente…

    Session A

    SET TRANSACTION ISOLATION LEVEL REPEATABLE READ // READ COMMITTED // READ UNCOMMITTED // SERIALIZABLE

    BEGIN TRANSACTION

    INSERT INTO Tabla VALUES('Pepe')

    O

    SELECT * FROM Tabla

    Session B

    INSERT INTO Tabla VALUES ('Pepita')

    Session C

    UPDATE Tabla SET NOMBRE = 'Juan' WHERE NOMBRE = 'Pepita'

    DELETE FROM Tabla WHERE NOMBRE = 'PEPE'

    Session D

    SELECT * FROM Tabla

     

     

    La unica que logro notar la diferencia es cuando uso el nivel “SERIALIZABLE”, que no puedo ejecutar ninguna de las otras sessiones.

    Pero cuando uso los otros niveles de aislamiento no noto diferencia alguna… Si uso en la transaccion una consulta unicamente de selección “SELECT” luego puedo ejecutar todas las secciones a excepción de la Session D “SELECT”… Pero cuando ejecuto un INSERT en la transaccion, solo puedo ejecutar la “Session B” de INSERT mientras que todas las demas se quedan en cola…

     

    Que estoy mal interpretando que no logro ver la diferencia, de antemano muchas gracias a todos…

    viernes, 25 de junio de 2010 21:38

Respuestas

  • Hola.

    No te preocupes, no es un tema sencillo. Y también es frecuente encontrarse con gente que cree tenerlo dominado y sin embargo tiene unos errores de concepto importantes. Voy a intentar explicarlo de una forma sencilla.

    Antes que el nivel de aislamiento y las transacciones, está el concepto de bloqueo. Un bloqueo es un mecanismo de protección del motor para que dos hilos no modifiquen simultáneamente el mismo dato. Los hay a nivel de fila, a nivel de página, de varias páginas y de tablas enteras. Incluso a nivel de base de datos, sólo del esquema, y algún otro más. Además, los tienes de distinto modo, una tabla de compatibilidades entre bloqueos, por así decirlo. Se pueden resumir en 2, compartidos y exclusivos, cada uno de ellos puede ser un "intento" de ser bloqueo o un bloqueo ya consumado. Y luego los bloqueos se dice que "se escalan". Si hay mucho bloqueos en una misma página de datos, se puede bloquear la página entera. Si se bloquea un importante número de páginas, se puede bloquear toda una tabla. Es un mecanismo para optimizar el rendimiento y reducir el coste de tener que revisar registro a registro qué es lo que está bloqueado y qué no.

    El nivel de aislamiento define cómo se elevarán los bloqueos, qué bloqueos por defecto se generan. Unas normas para el juego. Es algo que no se define para todas las transacciones, sino para cada transacción individual, con lo que puedes tener una transacción con unas normas y otra con otras normas. Como ves hasta aquí, es algo bastante complejo.

    El nivel de aislamiento más optimista y permisivo es "read uncommitted" o "leer lo no confimado". Las normas de este nivel no son un "vale todo", es sólo que se elevan menos bloqueos y los que se elevan para las lecturas son compartidos. Así, por ejemplo, si tienes una transacción "A" (del nivel que sea) que está abierta y en la que se realizaron modificaciones en un registro, pero todavía no se ha hecho un "commit", tú puedes leer el contenido de esa fila con la modificación ya hecha.

    Cabe la posibilidad de que luego esa transacción no se complete y se haga un rollback y tú habrás leído un dato que nunca llegó a estar confirmado. Pero en un global, estás leyendo de la base de datos lo que muy probablemente habrá dentro de unos pocos milisegundos, sin tener que esperar esos milisegundos. Salvo circunstancias muy concretas (que tengas que pintar una nómina o algo de ese nivel de criticidad) es el que yo recomiendo usar siempre. Los demás, a poca concurrencia que tengas, obtienes un sinfín de bloqueos. 

    El siguiente nivel es "read committed" o "leer lo confirmado". Es igual que el anterior, pero con la diferencia de que no podrás leer el dato hasta que no se haga "commit". Recuerda, siempre nos referimos al nivel de aislamiento de la transacción que lee, no de la transacción que escribe (que puede ser la que sea). En este nivel son frecuentes los bloqueos de intento de compartido, si existe algún bloqueo exclusivo (como el que hace un update o un delete), el registro no podrá ser leído hasta que dicho bloqueo no se libere.

    Los otros dos niveles son "repeatable read" y "serializable". El primero asegura "lecturas repetibles", es decir, en caso de que abra una trasacción y lea un conjunto de registros, se garantiza que eso que se haya leído se mantendrá intacto hasta que cierre la conexión (salvo, obviamente, las modificaciones que se hagan en la propia transacción). Y el último es el más restrictivo de todos, ya que se bloquea lo que se consulta y lo cercano, con el fin de que cada operación que se realice sea siempre de una en una (vamos, serializado). Estos dos niveles de aislamiento hay que evitarlos en la medida de lo posible, salvo que expresamente se deseen obtener dicho bloqueos. Los bloqueos que se elevan suelen ser de rangos de claves, con lo que el escalado a página y a tabla es muy frecuente.

    Para ver por ti mismo qué hace cada nivel, lo que debes hacer es abrir 3 sesiones, una para escribir, una para leer y otra para ver los bloqueos que se elevan (con sp_lock, por ejemplo). Haz las pruebas, mira a ver si te queda más o menos claro y si sigues con dudas, nos dices.

     


    Alberto López Grande (Visita mi blog en http://qwalgrande.blogspot.es/)
    lunes, 28 de junio de 2010 6:47
    Moderador

Todas las respuestas

  • Hola.

    La verdad es que de momento no lo has cogido. Léete este artículo de la web de El Guille, que explica de una forma sencilla cada nivel de aislamiento.

    http://www.guillesql.es/Articulos/SQLServerFAQ_Aislamiento_Transaccion_Isolation_Level.aspx

    Si después continúan tus dudas, nos dices.

     


    Alberto López Grande (Visita mi blog en http://qwalgrande.blogspot.es/)
    sábado, 26 de junio de 2010 13:21
    Moderador
  • Hola.

    La verdad es que de momento no lo has cogido. Léete este artículo de la web de El Guille, que explica de una forma sencilla cada nivel de aislamiento.

    http://www.guillesql.es/Articulos/SQLServerFAQ_Aislamiento_Transaccion_Isolation_Level.aspx

    Si después continúan tus dudas, nos dices.

     


    Alberto López Grande (Visita mi blog en http://qwalgrande.blogspot.es/)

    Hola Alberto que tal… Si tienes razón no logro captar la idea para nada. Guiándome en el link que me distes “el cual te agradezco” y en este “el cual también me pareció muy bueno”  http://manuals.sybase.com/onlinebooks/group-asarc/svs11001/tsqlsp/@Generic__BookTextView/43167;hf=0;lang=es

    Tengo lo siguiente…

     

    READ UNCOMMITTED

    SQL Server garantiza que los datos escritos por una transacción representen los datos reales. Este nivel evita que otras transacciones escriban sobre los mismos datos antes de que la transacción se consigne. Las otras transacciones pueden leer los datos no consignados.

    Evita que otras transacciones cambien los datos que ya han sido modificados (mediante insert, delete, update , etc.) por una transacción no consignada. Las otras transacciones se bloquean para que no modifiquen los datos hasta que la transacción se haya consignado. No obstante, las otras transacciones todavía pueden leer los datos no consignados, lo que da lugar a lecturas sucias.

    En conclusión, según esto, si hago esto en una primera session:

    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

    GO

    BEGIN TRANSACTION;

              INSERT INTO Tabla VALUES ('Pepe')

     

    Luego podre realizar únicamente consultas INSERT desde otra session y si realizo cualquier otra quedara en cola … Pese a esto, cuando hago por ejemplo un SELECT el cual se queda en cola y luego se ejecuta el COMMITTED de la transacion, me devuelven los datos obtenidos después de realizar la transacción.

     

    READ COMMITTED

    SQL Server garantiza que los datos leídos por una transacción representen los datos reales, no los datos del proceso de otra transacción no consignada. Este es el nivel de aislamiento predeterminado soportado por SQL Server.

    Evita las lecturas sucias. Estas lecturas tienen lugar cuando una transacción modifica una fila y luego una segunda transacción lee esa misma fila antes de que la primera transacción haya podido consignar el cambio. Si la primera transacción revierte el cambio, la información leída por la segunda transacción se convierte en inválida.

    En conclusión, según esto, si tengo un registro

    Nombre

    Carlos

    Jose

    Luego si hago esto en una primera session:

    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

    GO

    BEGIN TRANSACTION;

              INSERT INTO Tabla VALUES ('Pepe')

    Y en otra session hago

    SELECT NOMBRE FROM Tabla

     

    Los datos seran los mismos, hasta que se ejecuto el COMMIT de la transaccion, es decir

     

    Nombre

    Carlos

    Jose

     

     

    Pero si hago exactamente lo mismo de la transacción anterior pasa lo mismo. “Si ejecuto un SELECT queda en cola y cuando el COMMIT de la transacción me trae los datos obtenidos después de realizar la transacción....

    sábado, 26 de junio de 2010 21:29
  •  

    READ REPEATABLE

    Evita las lecturas no repetidas. Estas lecturas tienen lugar cuando una transacción lee una fila y luego una segunda transacción modifica dicha fila. Si la segunda transacción consigna el cambio, las lecturas subsiguientes realizadas por la primera transacción producen resultados diferentes a los de la primera lectura.

     

    Si tengo en una tabla los campos

    Nombre

    Carlos

    Jose

     

    Si hago…

    SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

    BEGIN TRANSACTION

              SELECT * FROM Tabla WHERE NOMBRE = 'PEPE'

     

    No tendre ningun resultado devuelto…

    Si luego hago en otra sesión

    INSERT INTO Tabla VALUES ('PEPE', 'ÑAÑES')

    Y ejecuto de nuevo en la transaccion… Tendre un registro

    SELECT * FROM Tabla WHERE NOMBRE = 'PEPE'

    Cuando ejecuto estos ejemplos se ejecutan y me traen los resultados pero si en vez de usar REPEATABLE READ uso otra me trae exactamente lo mismo.

     

    SERIALIZABLE

    Evita las lecturas fantasmas. Estas lecturas tienen lugar cuando una transacción lee un conjunto de filas que cumplen una condición de búsqueda y luego una segunda transacción modifica los datos (mediante una instrucción insert , delete , update , etc.). Si la primera transacción repite la lectura con las mismas condiciones de búsqueda, el conjunto de filas resultante es distinto.

    Es decir, si hago esto… En una sesión

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

    BEGIN TRANSACTION

              SELECT * FROM Tabla WHERE NOMBRE = 'PEPE'

    Luego en otra session hago esto…

    INSERT INTO Tabla VALUES('Pepe', 'Ramirez')

    Si hago de nuevo en la session de la transaccion…

    SELECT * FROM Tabla WHERE NOMBRE = 'PEPE'

    Me traera los datos actualizados… Pero esto no pasa, cuando ejecuto una con SERIALIZABLE lo que obtengo es un bloqueo que no me da nisiquiera INSERTAR al momento si no que coloca a la consulta en cola para esperar que finaliza la transaccion…

     

    En verdad no entiendo la idea… He trato de realizar todas estas consultas desde diferentes ventanas de SQL Server 2008 y es lo mismo…

    Que estoy mal interpretando en verdad no entiendo…

    Muchas gracias de nuevo…

    sábado, 26 de junio de 2010 21:29
  • Hola.

    La verdad es que de momento no lo has cogido. Léete este artículo de la web de El Guille, que explica de una forma sencilla cada nivel de aislamiento.

    http://www.guillesql.es/Articulos/SQLServerFAQ_Aislamiento_Transaccion_Isolation_Level.aspx

    Si después continúan tus dudas, nos dices.

     


    Alberto López Grande (Visita mi blog en http://qwalgrande.blogspot.es/)

     

     

    Hola que tal como estas…

    Aun no logro entender bien… Es que mira…

    Esto es lo que se define de nivel de aislamiento…

     

    “El nivel de aislamiento de una transacción (transaction isolation level) define el grado en que se aísla una transacción de las modificaciones de recursos o datos realizadas por otras transacciones.”

    Entonces READ UNCOMMITED se define asi…

    “Implementa lecturas sucias. Es posible leer datos sucios o no comprometidos, los valores en los datos se pueden cambiar y las filas pueden aparecer o desaparecer en el conjunto de datos antes de que finalice la transacción.”

    Lo que yo entiendo de alli es que si por ejemplo ejecuto una transaccion, mientras esta se ejecuta en otras sessiones se pueden consultar los datos que la primera transaccion esta ejecutandose.

    Pero yo no puedo nisiquiera realizar un SELECT en una tabla en cuya transaccion realizo alguna modificacion… Entonces por que dice que se pueden realizar lecturas sucias?

     

    En verdad disculpa una vez mas la molestia pero por mas que le busco la vuelta nada…

    domingo, 27 de junio de 2010 21:58
  • Hola.

    No te preocupes, no es un tema sencillo. Y también es frecuente encontrarse con gente que cree tenerlo dominado y sin embargo tiene unos errores de concepto importantes. Voy a intentar explicarlo de una forma sencilla.

    Antes que el nivel de aislamiento y las transacciones, está el concepto de bloqueo. Un bloqueo es un mecanismo de protección del motor para que dos hilos no modifiquen simultáneamente el mismo dato. Los hay a nivel de fila, a nivel de página, de varias páginas y de tablas enteras. Incluso a nivel de base de datos, sólo del esquema, y algún otro más. Además, los tienes de distinto modo, una tabla de compatibilidades entre bloqueos, por así decirlo. Se pueden resumir en 2, compartidos y exclusivos, cada uno de ellos puede ser un "intento" de ser bloqueo o un bloqueo ya consumado. Y luego los bloqueos se dice que "se escalan". Si hay mucho bloqueos en una misma página de datos, se puede bloquear la página entera. Si se bloquea un importante número de páginas, se puede bloquear toda una tabla. Es un mecanismo para optimizar el rendimiento y reducir el coste de tener que revisar registro a registro qué es lo que está bloqueado y qué no.

    El nivel de aislamiento define cómo se elevarán los bloqueos, qué bloqueos por defecto se generan. Unas normas para el juego. Es algo que no se define para todas las transacciones, sino para cada transacción individual, con lo que puedes tener una transacción con unas normas y otra con otras normas. Como ves hasta aquí, es algo bastante complejo.

    El nivel de aislamiento más optimista y permisivo es "read uncommitted" o "leer lo no confimado". Las normas de este nivel no son un "vale todo", es sólo que se elevan menos bloqueos y los que se elevan para las lecturas son compartidos. Así, por ejemplo, si tienes una transacción "A" (del nivel que sea) que está abierta y en la que se realizaron modificaciones en un registro, pero todavía no se ha hecho un "commit", tú puedes leer el contenido de esa fila con la modificación ya hecha.

    Cabe la posibilidad de que luego esa transacción no se complete y se haga un rollback y tú habrás leído un dato que nunca llegó a estar confirmado. Pero en un global, estás leyendo de la base de datos lo que muy probablemente habrá dentro de unos pocos milisegundos, sin tener que esperar esos milisegundos. Salvo circunstancias muy concretas (que tengas que pintar una nómina o algo de ese nivel de criticidad) es el que yo recomiendo usar siempre. Los demás, a poca concurrencia que tengas, obtienes un sinfín de bloqueos. 

    El siguiente nivel es "read committed" o "leer lo confirmado". Es igual que el anterior, pero con la diferencia de que no podrás leer el dato hasta que no se haga "commit". Recuerda, siempre nos referimos al nivel de aislamiento de la transacción que lee, no de la transacción que escribe (que puede ser la que sea). En este nivel son frecuentes los bloqueos de intento de compartido, si existe algún bloqueo exclusivo (como el que hace un update o un delete), el registro no podrá ser leído hasta que dicho bloqueo no se libere.

    Los otros dos niveles son "repeatable read" y "serializable". El primero asegura "lecturas repetibles", es decir, en caso de que abra una trasacción y lea un conjunto de registros, se garantiza que eso que se haya leído se mantendrá intacto hasta que cierre la conexión (salvo, obviamente, las modificaciones que se hagan en la propia transacción). Y el último es el más restrictivo de todos, ya que se bloquea lo que se consulta y lo cercano, con el fin de que cada operación que se realice sea siempre de una en una (vamos, serializado). Estos dos niveles de aislamiento hay que evitarlos en la medida de lo posible, salvo que expresamente se deseen obtener dicho bloqueos. Los bloqueos que se elevan suelen ser de rangos de claves, con lo que el escalado a página y a tabla es muy frecuente.

    Para ver por ti mismo qué hace cada nivel, lo que debes hacer es abrir 3 sesiones, una para escribir, una para leer y otra para ver los bloqueos que se elevan (con sp_lock, por ejemplo). Haz las pruebas, mira a ver si te queda más o menos claro y si sigues con dudas, nos dices.

     


    Alberto López Grande (Visita mi blog en http://qwalgrande.blogspot.es/)
    lunes, 28 de junio de 2010 6:47
    Moderador
  • Cierro thread porque el OP ha iniciado uno nuevo siguiendo este tema.
    Gustavo Larriera Sosa, Microsoft MVP | ascii164.blogspot.com | /*Este mensaje se proporciona tal como es, sin garantías de ninguna clase.*/
    lunes, 28 de junio de 2010 14:58
    Moderador