Nivel de aislamiento de transacciones

La versión actual de la página aún no ha sido revisada por colaboradores experimentados y puede diferir significativamente de la versión revisada el 29 de diciembre de 2019; las comprobaciones requieren 20 ediciones .

El nivel de aislamiento de transacciones  es un valor condicional que determina hasta qué punto, como resultado de la ejecución de transacciones lógicamente paralelas en el DBMS, se permiten datos inconsistentes. La escala de niveles de aislamiento de transacciones contiene una serie de valores ordenados de menor a mayor; un mayor nivel de aislamiento corresponde a una mejor consistencia de los datos, pero su uso puede reducir el número de transacciones físicamente paralelas. Por el contrario, un nivel de aislamiento más bajo permite transacciones más paralelas, pero reduce la precisión de los datos. Por lo tanto, al elegir el nivel de aislamiento de transacciones utilizado, el desarrollador del sistema de información, en cierta medida, ofrece la posibilidad de elegir entre la velocidad de trabajo y garantizar la consistencia garantizada de los datos recibidos del sistema.

Problemas con la concurrencia usando transacciones

Cuando las transacciones se ejecutan en paralelo , son posibles los siguientes problemas:

Considere situaciones en las que estos problemas pueden ocurrir.

Actualización perdida

La situación cuando, cuando un bloque de datos es cambiado simultáneamente por diferentes transacciones, uno de los cambios se pierde.

Supongamos que hay dos transacciones ejecutándose al mismo tiempo:

transacción 1 transacción 2
UPDATE tbl1 SET f2=f2+20 WHERE f1=1; UPDATE tbl1 SET f2=f2+25 WHERE f1=1;

En ambas transacciones, el valor del campo f2 cambia, al completarse, el valor del campo debe incrementarse en 45. De hecho, puede ocurrir la siguiente secuencia de acciones:

  1. Ambas transacciones leen simultáneamente el estado actual del campo. Aquí no se requiere concurrencia física exacta, es suficiente que la segunda operación de lectura en orden se complete antes de que otra transacción escriba su resultado.
  2. Ambas transacciones calculan el valor del nuevo campo sumando 20 y 25, respectivamente, al valor leído anteriormente.
  3. Las transacciones intentan volver a escribir el resultado del cálculo en el campo f2. Dado que es físicamente imposible realizar dos escrituras al mismo tiempo, en realidad una de las operaciones de escritura se realizará antes y la otra después. La segunda operación de escritura sobrescribirá el resultado de la primera.

Como resultado, el valor del campo f2, al completar ambas transacciones, puede aumentar no en 45, sino en 20 o 25, es decir, una de las transacciones de cambio de datos "desaparecerá".

Lectura "sucia"

Lectura de datos agregados o modificados por una transacción que luego no se confirmará (reversión).

Supongamos que tenemos dos transacciones abiertas por diferentes aplicaciones que ejecutan las siguientes sentencias SQL:

transacción 1 transacción 2
UPDATE tbl1 SET f2=f2+1 WHERE f1=1;
SELECT f2 FROM tbl1 WHERE f1=1;
ROLLBACK WORK;

En la transacción 1 se cambia el valor del campo f2 y luego en la transacción 2 se selecciona el valor de este campo. Después de eso, se revierte la transacción 1. Como resultado, el valor recibido por la segunda transacción diferirá del valor almacenado en la base de datos.

Lectura no repetida

La situación cuando, al volver a leer dentro de la misma transacción, los datos leídos anteriormente resultan ser cambiados.

Supongamos que hay dos transacciones abiertas por diferentes aplicaciones en las que se ejecutan las siguientes sentencias SQL :

transacción 1 transacción 2
SELECT f2 FROM tbl1 WHERE f1=1;
UPDATE tbl1 SET f2=f2+3 WHERE f1=1;
COMMIT;
SELECT f2 FROM tbl1 WHERE f1=1;

En la transacción 2, se selecciona el valor del campo f2, luego en la transacción 1, se cambia el valor del campo f2. Si vuelve a intentar seleccionar un valor del campo f2 en la transacción 2, se obtendrá un resultado diferente. Esta situación es especialmente inaceptable cuando los datos se leen para modificarlos parcialmente y volver a escribirlos en la base de datos.

Lectura de "fantasmas"

La situación cuando, durante la lectura repetida dentro de la misma transacción, la misma selección da diferentes conjuntos de filas.

Supongamos que hay dos transacciones abiertas por diferentes aplicaciones que ejecutan las siguientes sentencias SQL:

transacción 1 transacción 2
SELECT SUM(f2) FROM tbl1;
INSERT INTO tbl1 (f1,f2) VALUES (15,20);
COMMIT;
SELECT SUM(f2) FROM tbl1;

La transacción 2 ejecuta una declaración SQL que utiliza todos los valores del campo f2. Luego, se inserta una nueva fila en la transacción 1, lo que provoca que la nueva ejecución de la instrucción SQL en la transacción 2 produzca un resultado diferente. Esta situación se denomina lectura fantasma (phantom reading). Se diferencia de la lectura no repetible en que el resultado del acceso repetido a los datos ha cambiado no debido al cambio/eliminación de los datos en sí, sino a la aparición de nuevos datos (fantasmas).

Niveles de aislamiento

El " nivel de aislamiento de transacciones " se refiere al grado de protección proporcionado por los mecanismos internos del DBMS (es decir, que no requiere programación especial) de todos o algunos de los tipos anteriores de inconsistencias de datos que ocurren durante la ejecución paralela de transacciones. El estándar SQL-92 define una escala de cuatro niveles de aislamiento: Lectura no confirmada, Lectura confirmada, Lectura repetible, Serializable. El primero de ellos es el más débil, el último es el más fuerte, cada subsiguiente incluye a todos los anteriores.

Lectura no confirmada (lectura de datos no confirmados)

El nivel de aislamiento más bajo (primero) [1] . Si varias transacciones paralelas intentan modificar la misma fila de la tabla, la fila final tendrá un valor determinado por el conjunto completo de transacciones completadas con éxito. En este caso, es posible leer no solo datos lógicamente inconsistentes, sino también datos cuyos cambios aún no se han registrado.

Una forma típica de implementar este nivel de aislamiento es bloquear los datos mientras se ejecuta el comando de cambio, lo que garantiza que los comandos de modificación en las mismas filas que se ejecutan en paralelo se ejecuten secuencialmente y ninguno de los cambios se pierda. Las transacciones de solo lectura nunca se bloquean bajo este nivel de aislamiento.

Lectura comprometida (lectura de datos fijos)

La mayoría de los SGBD industriales, en particular Microsoft SQL Server , PostgreSQL y Oracle , utilizan este nivel de forma predeterminada. En este nivel, se proporciona protección contra borrador, lectura "sucia", sin embargo, durante la operación de una transacción, otra puede completarse con éxito y se corrigen los cambios realizados por ella. Como resultado, la primera transacción funcionará con un conjunto de datos diferente.

La implementación de una lectura completa se puede basar en uno de dos enfoques: bloqueo o control de versiones.

Bloqueo de datos legibles y mutables. Consiste en el hecho de que la transacción de escritura bloquea los datos mutables para las transacciones de lectura que operan en el nivel de compromiso de lectura o superior hasta que se completa, evitando así la lectura "sucia", y los datos bloqueados por la transacción de lectura se liberan inmediatamente después de la finalización de la Operación SELECCIONAR (por lo tanto, una situación de "lectura no repetible" puede ocurrir en un nivel de aislamiento dado). Guardar múltiples versiones de filas que cambian en paralelo. Cada vez que se cambia una fila, el SGBD crea una nueva versión de esta fila, con lo que la transacción que cambió los datos sigue funcionando, mientras que cualquier otra transacción de “lectura” devuelve la última versión comprometida. La ventaja de este enfoque es que proporciona más velocidad, ya que evita el bloqueo. Sin embargo, requiere, en comparación con el primero, una cantidad significativamente mayor de RAM, que se gasta en almacenar versiones de filas. Además, cuando varias transacciones modifican datos en paralelo, puede crear una situación en la que varias transacciones simultáneas realicen cambios incoherentes en los mismos datos (dado que no hay bloqueos, nada evitará que esto suceda). Luego, la transacción que se confirma primero guardará sus cambios en la base de datos principal, y las transacciones paralelas restantes serán imposibles de confirmar (ya que esto conducirá a la pérdida de la actualización de la primera transacción). Lo único que el DBMS puede hacer en tal situación es deshacer el resto de las transacciones y emitir un mensaje de error "El registro ya se modificó".

Los desarrolladores de DBMS eligen un método de implementación específico y, en algunos casos, se puede personalizar. Entonces, de forma predeterminada, MS SQL usa bloqueos, pero (en la versión 2005 y posteriores) cuando se establece el parámetro READ_COMMITTED_SNAPSHOT, la base de datos cambia a la estrategia de control de versiones, Oracle inicialmente funciona solo de acuerdo con el esquema de control de versiones. Informix , puede evitar conflictos entre transacciones de lectura y escritura configurando el parámetro de configuración USELASTCOMMITTED (desde la versión 11.1), que hará que la transacción de lectura reciba los últimos datos confirmados [2]

Lectura repetible

El nivel en el que una transacción de lectura "no ve" cambios en los datos que leyó anteriormente. Al mismo tiempo, ninguna otra transacción puede cambiar los datos leídos por la transacción actual hasta que finalice.

Los bloqueos en modo compartido se aplican a todos los datos leídos por cualquier instrucción en una transacción y se mantienen hasta que se completa la transacción. Esto evita que otras transacciones modifiquen las filas que leyó la transacción pendiente. Sin embargo, otras transacciones pueden insertar nuevas líneas que coincidan con las condiciones de búsqueda de las instrucciones contenidas en la transacción actual. Cuando la transacción actual reinicia la declaración, se obtendrán nuevas filas, lo que dará como resultado una lectura fantasma. Dado que los bloqueos compartidos se mantienen hasta el final de la transacción, en lugar de liberarse al final de cada declaración, el grado de concurrencia es menor que con el nivel de aislamiento de LECTURA COMPROMETIDA. Por lo tanto, generalmente no se recomienda utilizar este y niveles de transacción superiores innecesariamente.  

Serializable

El más alto nivel de aislamiento; las transacciones están completamente aisladas entre sí, cada una se ejecuta como si no hubiera transacciones paralelas. Solo en este nivel las transacciones concurrentes no están sujetas al efecto de "lectura fantasma".

Compatibilidad con el aislamiento de transacciones en DBMS reales

Los DBMS transaccionales no siempre son compatibles con los cuatro niveles y también pueden introducir niveles adicionales. También hay varios matices al proporcionar aislamiento.

Entonces, en principio, Oracle no soporta el nivel cero, ya que su implementación de transacciones excluye las “lecturas sucias”, y formalmente no permite establecer el nivel de lectura Repetible, es decir, soporta solo Lectura comprometida (por defecto) y Serializable. Al mismo tiempo, a nivel de comandos individuales, en realidad garantiza la repetibilidad de lectura (si el comando SELECT en la primera transacción selecciona un conjunto de filas de la base de datos, y en este momento una segunda transacción paralela cambia algunas de estas filas, entonces el conjunto de resultados recibido por la primera transacción contendrá filas sin cambios, como si no hubiera una segunda transacción). Oracle también admite las llamadas transacciones de SÓLO LECTURA, que se ajustan a Serializable pero no pueden cambiar los datos en sí.

Microsoft SQL Server admite los cuatro niveles estándar de aislamiento de transacciones y, además, el nivel SNAPSHOT, en el que la transacción ve el estado de los datos que se confirmaron antes de iniciarse, así como los cambios realizados por sí misma, es decir, se comporta como si recibió lanzando una instantánea de los datos de la base de datos y trabajando con ella. La diferencia con Serialized es que no se utilizan bloqueos, pero como resultado, es posible que no sea posible realizar cambios si una transacción simultánea ha cambiado los mismos datos anteriormente; en este caso, la segunda transacción, al intentar COMMIT, generará un mensaje de error y se cancelará.

Comportamiento en diferentes niveles de aislamiento

"+" - previene, "-" - no previene.

nivel de aislamiento lectura fantasma Lectura no repetitiva Lectura "sucia" Actualización perdida [3]
SERIALIZABLE + + + +
LECTURA REPETIBLE - + + +
LEER COMPROMETIDO - - + +
LEER SIN COMPROMISO - - - + [4]

Notas

  1. Comprensión de los niveles de aislamiento . Consultado el 14 de noviembre de 2011. Archivado desde el original el 18 de mayo de 2012.
  2. Parámetro de configuración USELASTCOMMITTED http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.adref.doc/ids_adr_0186.htm
  3. Comprensión de los niveles de aislamiento de transacciones disponibles . Consultado el 30 de agosto de 2012. Archivado desde el original el 14 de octubre de 2012.
  4. Paul Wilton, John Colby. Comienzo de SQL . — John Wiley & Sons, 2005-03-04. - S. 319. - 522 pág. - ISBN 978-0-7645-9632-2 . Archivado el 22 de abril de 2021 en Wayback Machine .