Aislamiento serializable - Amazon Redshift

Aislamiento serializable

Algunas aplicaciones no solo requieren la ejecución simultánea de consultas y cargas, sino también la capacidad de escribir en distintas tablas o en la misma tabla de manera simultánea. En este contexto, simultánea significa "superpuesta", no "programada para que se ejecute exactamente al mismo tiempo". Dos transacciones se consideran simultáneas si la segunda comienza antes de que se confirme la primera. Las operaciones concurrentes pueden originarse en sesiones diferentes controladas por el mismo usuario o por usuarios diferentes.

nota

Amazon Redshift admite el comportamiento de confirmación automática predeterminado en el que cada comando SQL ejecutado por separado se confirma individualmente. Si incluye un conjunto de comandos en un bloque de transacciones (definido por instrucciones BEGIN y END), el bloque se confirma como una transacción, de manera que puede revertirse de ser necesario. Las excepciones a este comportamiento son los comandos TRUNCATE y VACUUM, que confirman automáticamente todos los cambios pendientes realizados en la transacción actual.

Algunos clientes SQL emiten los comandos BEGIN y COMMIT automáticamente, por lo que el cliente controla si un grupo de instrucciones se ejecuta como una transacción o si cada instrucción individual se ejecuta como su propia transacción. Consulte la documentación de la interfaz que está utilizando. Por ejemplo, cuando se utiliza el controlador JDBC de Amazon Redshift, una cadena PreparedStatement de JDBC con consulta que contiene varios comandos SQL (separados por punto y coma) ejecuta todas las instrucciones como una sola transacción. Por el contrario, si utiliza SQL Workbench/J y establece AUTO COMMIT ON, si ejecuta varias instrucciones, cada una de ellas se ejecuta como una transacción propia.

Las operaciones de escritura simultáneas son compatibles con Amazon Redshift en modo protegido, con bloqueos de escritura en las tablas y el principio de aislamiento serializable. El aislamiento serializable conserva la ilusión de que una transacción que se ejecuta en una tabla es la única transacción ejecutándose en ella. Por ejemplo, dos transacciones que se ejecutan de manera simultánea, T1 y T2, deben generar los mismos resultados que al menos uno de los siguientes:

  • T1 y T2 se ejecutan en serie en ese orden.

  • T2 y T1 se ejecutan en serie en ese orden.

Las transacciones simultáneas son invisibles entre sí, no pueden detectar los cambios de la otra. Cada transacción simultánea creará una instantánea de base de datos al comienzo de la transacción. Una instantánea de base de datos se crea dentro de una transacción con la primera aparición de la mayoría de las instrucciones SELECT, los comandos DML como COPY, DELETE, INSERT, UPDATE y TRUNCATE, y los siguientes comandos DDL:

  • ALTER TABLE (para agregar o eliminar columnas)

  • CREATE TABLE

  • DROP TABLE

  • TRUNCATE TABLE

Si una ejecución en serie de las transacciones simultáneas produce los mismos resultados que la ejecución simultánea, estas transacciones se consideran “serializables” y pueden ejecutarse de manera segura. Si ninguna ejecución en serie de esas transacciones puede producir los mismos resultados, la transacción que ejecuta una instrucción que podría afectar la capacidad de serialización se anula y revierte.

Las tablas de catálogo del sistema (PG) y otras tablas del sistema de Amazon Redshift (STL y STV) no se bloquean en una transacción. Por lo tanto, los cambios realizados en los objetos de base de datos que surjan de las operaciones DDL y TRUNCATE son visibles con cualquier transacción simultánea cuando se confirman.

Por ejemplo, supongamos que la tabla A existe en la base de datos al momento en que comienzan dos transacciones simultáneas, T1 y T2. Supongamos que T2 devuelve una lista de tablas al seleccionar las de la tabla de catálogo PG_TABLES. Luego T1 elimina la tabla A y confirma los cambios y, a continuación, T2 vuelve a especificar las tablas. La tabla A ya no aparece en la lista. Si T2 intenta ejecutar una consulta en la tabla eliminada, Amazon Redshift devuelve un error de tipo “la relación no existe”. La consulta de catálogo que le devuelve la lista de tablas a T2 o que verifica la existencia de la tabla A no se encuentra sujeta a las mismas reglas de aislamiento que las operaciones que se realizan en las tablas de usuario.

Las transacciones de las actualizaciones de estas tablas se ejecutan en un modo de aislamiento de lectura confirmada. Las tablas de catálogo con el prefijo PG no son compatibles con el aislamiento de la instantánea.

Aislamiento serializable para tablas de sistema y tablas de catálogo

Una instantánea de base de datos también se crea en una transacción para cualquier consulta SELECT que referencia una tabla creada por un usuario o una tabla de sistema de Amazon Redshift (STL o STV). Las consultas SELECT que no hacen referencia a ninguna tabla no crean una instantánea de base de datos de transacción nueva. Las instrucciones INSERT, DELETE y UPDATE que realizan operaciones únicamente en tablas de catálogo del sistema (PG) tampoco crean una instantánea de base de datos de transacción nueva.

Cómo corregir errores de aislamiento serializable

ERROR:1023 DETAIL: Serializable isolation violation on a table in Redshift

Cuando Amazon Redshift detecta un error de aislamiento serializable, se muestra un mensaje de error como el siguiente.

ERROR:1023 DETAIL: Serializable isolation violation on table in Redshift

Para solucionar el error de aislamiento serializable, puede probar los métodos siguientes:

  • Volver a intentar la transacción cancelada.

    Amazon Redshift detectó que una carga de trabajo simultánea no es serializable. Sugiere que hay deficiencias en la lógica de la aplicación, que por lo general se pueden solucionar si se intenta realizar la transacción en la que se encontró el error de nuevo. Si el problema persiste, pruebe uno de los métodos siguientes.

  • Mover cualquier operación que no tenga que estar en la misma transacción atómica fuera de la transacción.

    Este método se aplica cuando las operaciones individuales dentro de dos transacciones tienen referencias cruzadas entre sí de forma que pueden afectar al resultado de la otra transacción. Por ejemplo, las dos sesiones siguientes inician una transacción cada una.

    Session1_Redshift=# begin;
    Session2_Redshift=# begin;

    El resultado de la instrucción SELETCT en cada transacción se podría ver afectado por una instrucción INSERT en la otra. Dicho de otro modo, suponga que ejecuta las siguientes instrucciones en serie, en cualquier orden. En cada caso, el resultado es que una de las instrucciones SELECT devuelve una fila más que si las transacciones se ejecutaran de forma simultánea. No hay ningún orden en que las operaciones se puedan ejecutar en serie que produzca el mismo resultado que cuando se ejecutan de forma simultánea. Así, la última operación que se ejecuta da lugar a un error de aislamiento serializable.

    Session1_Redshift=# select * from tab1; Session1_Redshift=# insert into tab2 values (1);
    Session2_Redshift=# insert into tab1 values (1); Session2_Redshift=# select * from tab2;

    En muchos casos, el resultado de las instrucciones SELECT no es importante. Dicho de otro modo, la atomicidad de las operaciones en las transacciones no es importante. En estos casos, saque las instrucciones SELECT de sus transacciones, como se muestra en los ejemplos siguientes.

    Session1_Redshift=# begin; Session1_Redshift=# insert into tab1 values (1) Session1_Redshift=# end; Session1_Redshift=# select * from tab2;
    Session2_Redshift # select * from tab1; Session2_Redshift=# begin; Session2_Redshift=# insert into tab2 values (1) Session2_Redshift=# end;

    En estos ejemplos, no hay ninguna referencia cruzada en las transacciones. Las dos instrucciones INSERT no se ven afectadas entre sí. En estos ejemplo, hay al menos un orden en el que las transacciones se pueden ejecutar en serie y producir el mismo resultado que si se ejecutan de manera simultánea. Estos significa que las transacciones son serializables.

  • Obligue a la serialización bloqueando todas las tablas en cada sesión.

    El comando LOCK bloquea operaciones que dan lugar a errores de aislamiento serializable. Cuando utilice el comando LOCK, asegúrese de hacer lo siguiente:

    • Bloquee todas las tablas que se ven afectadas por la transacción, incluidas aquellas afectadas por instrucciones SELECT de solo lectura dentro de la transacción.

    • Bloquee las tablas en el mismo orden, con independencia del orden en que se ejecutan las operaciones.

    • Bloquee todas las tablas al principio de la transacción, antes de llevar a cabo alguna operación.

  • Utilizar el aislamiento de instantáneas para transacciones simultáneas

    Utilice un comando ALTER DATABASE con aislamiento de instantáneas. Para obtener más información sobre el parámetro SNAPSHOT para ALTER DATABASE, consulte Parámetros.

ERROR:1018 DETAIL: Relation does not exist

Cuando ejecuta operaciones simultáneas de Amazon Redshift en sesiones diferentes, se muestra un mensaje de error como el siguiente.

ERROR: 1018 DETAIL: Relation does not exist.

Las transacciones en Amazon Redshift utilizan el aislamiento de la instantánea. Una vez que se inicia una transacción, Amazon Redshift toma una instantánea de la base de datos. En todo el ciclo de vida de la transacción, la transacción realiza las operaciones en el estado de la base de datos como se refleja en la instantánea. Si la transacción realiza la lectura desde una tabla que no existe en la instantánea, arroja el mensaje de error 1018 mostrado anteriormente. Incluso cuando otra transacción simultánea crea una tabla después de que la transacción haya tomado la instantánea, la transacción no puede realizar la lectura desde la tabla recién creada.

Para solucionar este error de serialización del aislamiento, puede intentar cambiar el inicio de la transacción a un punto en el que sepa que existe la tabla.

Si otra transacción crea la tabla, este punto será después de que se haya confirmado la transacción. Además, asegúrese de que no se haya confirmado ninguna transacción simultánea que pueda haber eliminado la tabla.

session1 = # BEGIN; session1 = # DROP TABLE A; session1 = # COMMIT;
session2 = # BEGIN;
session3 = # BEGIN; session3 = # CREATE TABLE A (id INT); session3 = # COMMIT;
session2 = # SELECT * FROM A;

La última operación que ejecuta session2 como la operación de lectura da lugar a un error de aislamiento serializable. Este error ocurre cuando session2 toma una instantánea y la tabla ya ha sido eliminada por una session1 confirmada. En otras palabras, aunque una session3 simultánea haya creado la tabla, la session2 no ve la tabla porque no está en la instantánea.

Para resolver este error, puede reordenar las sesiones de la siguiente manera.

session1 = # BEGIN; session1 = # DROP TABLE A; session1 = # COMMIT;
session3 = # BEGIN; session3 = # CREATE TABLE A (id INT); session3 = # COMMIT;
session2 = # BEGIN; session2 = # SELECT * FROM A;

Cuando session2 toma su instantánea, session3 ya se ha confirmado y la tabla está en la base de datos. La session2 puede leer desde la tabla sin ningún error.