Quiero reemplazar todo el contenido de una tabla, sin afectar las SELECTdeclaraciones entrantes durante el proceso.
El caso de uso es tener una tabla que almacene la información del buzón que se extrae regularmente y que debe almacenarse en una tabla PostgreSQL. Hay muchos clientes que usan una aplicación que consulta constantemente esa misma tabla.
Normalmente, haría algo como (pseudocódigo entrante) ...
BEGIN TRANSACTION
TRUNCATE TABLE
INSERT INTO
COMMIT
Pero desafortunadamente la tabla no se puede leer durante este proceso; debido al tiempo que lleva INSERT INTOcompletarlo. La mesa está cerrada.
En MySQL, habría usado su RENAME TABLEcomando atómico para evitar estos problemas ...
CREATE TABLE table_new LIKE table;
INSERT INTO table_new;
RENAME TABLE table TO table_old, table_new TO table; *atomic operation*
DROP TABLE table_old;
¿Cómo podría lograr esto en PostgreSQL?
A los fines de esta pregunta, puede suponer que no estoy usando claves foráneas.
fuente

TRUNCATEcomando adquirirá un bloqueo AccessExclusive en la tabla, por lo que nadie más podrá leer de la tabla hasta que esa transacción se confirme o se revierta.deleteen su lugartruncateserá más lento, pero sin bloquear lectores. ¿Cuántas filas necesitas eliminar?DELETEyINSERTsería demasiado largo.Respuestas:
Correcto, el
TRUNCATE TABLEcomando que está ejecutando "... adquiere un bloqueo ACCESO EXCLUSIVO en cada tabla en la que opera ", por lo que en el primer bloque SQL que publicó, cualquier otro cliente que intente acceder a la tabla después de ese tiempo se bloqueará hasta queINSERTfinalice y ustedCOMMIT.Puede usar la misma solución alternativa que en su código específico de MySQL; Postgres admite aproximadamente la misma sintaxis y tendrá un comportamiento de bloqueo similar. Esto es:
Bonificación adicional: Postgres en realidad admite DDL transaccional, a diferencia de MySQL, por lo que en caso de que necesite ROLLBACK la transacción anterior, puede hacerlo de forma segura.
fuente
LOCK TABLEmétodo que sugirió, ¿tendría que desbloquearlo nuevamente antesCOMMITo se desbloqueará solo?_old-- LOCK TABLE "table" IN ROW EXCLUSIVE mode;) parece ser insuficiente para protegerlo de una actualización / inserción en la tabla fuente de acuerdo con las especificaciones. SeROW EXCLUSIVEpueden adquirir dos bloqueos sin ningún conflicto (consulte la Tabla 13.2 en postgresql.org/docs/10/explicit-locking.html#LOCKING-TABLES ). Para evitar actualizaciones de datos, necesita al menos unSHAREbloqueo.