sql >> Base de Datos >  >> RDS >> PostgreSQL

CREAR ESQUEMA SI NO EXISTE genera un error de clave duplicada

Esta es una pequeña verruga en la implementación de IF NOT EXISTS para tablas y esquemas. Básicamente, son un intento de upsert, y PostgreSQL no maneja las condiciones de carrera de manera limpia. Es seguro, pero feo.

Si el esquema se crea simultáneamente en otra sesión pero aún no se ha confirmado, entonces existe y no existe, según quién sea y cómo se vea. No es posible que otras transacciones "vean" el nuevo esquema en los catálogos del sistema porque no está comprometido, por lo que es una entrada en pg_namespace no es visible para otras transacciones. Así que CREATE SCHEMA / CREATE TABLE intenta crearlo porque, en lo que a él respecta, el objeto no existe.

Sin embargo, eso inserta una fila en una tabla con una restricción única. Las restricciones únicas deben poder ver las filas no confirmadas para poder funcionar. Entonces, la inserción se bloquea (se detiene) hasta la primera transacción que hizo CREATE se compromete o retrocede. Si se confirma, la segunda transacción se cancela porque intentó insertar una fila que viola una restricción única. CREATE SCHEMA no es lo suficientemente inteligente como para detectar este caso y volver a intentarlo.

Para arreglar correctamente este PostgreSQL probablemente necesitaría un bloqueo de predicado, donde podría bloquear el potencial para una fila . Esto podría agregarse como parte del trabajo actual para implementar UPSERT .

Para estos comandos en particular, PostgreSQL probablemente podría hacer una lectura sucia de los catálogos del sistema, donde puede ver los cambios no comprometidos. Luego, podría esperar a que la transacción no confirmada se confirme o revierta, volver a hacer la lectura sucia para ver si alguien más está esperando y volver a intentarlo. Pero esto tendría una condición de carrera en la que otra persona podría crear el esquema entre el momento en que realiza la lectura para verificarlo y el momento en que intenta crearlo.

Entonces IF NOT EXISTS las variantes tendrían que:

  • Compruebe si existe el esquema; si lo hace, termina sin hacer nada.
  • Intente crear la tabla
  • Si la creación falla debido a un error de restricción única, vuelva a intentarlo desde el principio
  • Si la creación de la tabla tiene éxito, finalice

Que yo sepa, nadie ha implementado eso, o lo intentaron y no fue aceptado. Habría posibles problemas con la tasa de consumo de ID de transacciones, etc., con este enfoque.

Creo que esto es una especie de error, pero es un tipo de error de "sí, lo sabemos", no un tipo de error de "lo solucionaremos". Siéntase libre de publicar en pgsql-bugs al respecto; como mínimo, la documentación debería mencionar esta advertencia sobre IF NOT EXISTS .

No recomiendo hacer DDL al mismo tiempo de esa manera.