Quiero reemplazar todo el contenido de una tabla, sin afectar las SELECT
declaraciones 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 INTO
completarlo. La mesa está cerrada.
En MySQL, habría usado su RENAME TABLE
comando 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
TRUNCATE
comando 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.delete
en su lugartruncate
será más lento, pero sin bloquear lectores. ¿Cuántas filas necesitas eliminar?DELETE
yINSERT
sería demasiado largo.Respuestas:
Correcto, el
TRUNCATE TABLE
comando 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 queINSERT
finalice 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 TABLE
método que sugirió, ¿tendría que desbloquearlo nuevamente antesCOMMIT
o 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 EXCLUSIVE
pueden 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 unSHARE
bloqueo.