Je souhaite remplacer l'intégralité du contenu d'une table, sans affecter les SELECT
instructions entrantes au cours du processus.
Le cas d'utilisation est d'avoir une table qui stocke des informations de boîte aux lettres qui sont régulièrement extraites et doit être stockée dans une table PostgreSQL. De nombreux clients utilisent une application qui interroge constamment cette même table.
Normalement, je ferais quelque chose comme (pseudocode entrant) ...
BEGIN TRANSACTION
TRUNCATE TABLE
INSERT INTO
COMMIT
Mais malheureusement, le tableau ne peut pas être lu pendant ce processus; en raison du temps qu'il faut INSERT INTO
pour terminer. La table est verrouillée.
Dans MySQL, j'aurais utilisé leur RENAME TABLE
commande atomique pour éviter ces problèmes ...
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;
Comment pourrais-je y parvenir dans PostgreSQL?
Aux fins de cette question, vous pouvez supposer que je n'utilise pas de clés étrangères.
la source
TRUNCATE
commande va acquérir un verrou AccessExclusive sur la table, donc personne d'autre ne pourra lire à partir de la table jusqu'à ce que cette transaction soit validée ou annulée.delete
place,truncate
il sera plus lent, mais sans bloquer les lecteurs. Combien de lignes devez-vous supprimer?DELETE
etINSERT
serait bien trop long.Réponses:
À droite, la
TRUNCATE TABLE
commande que vous exécutez "... acquiert un verrou ACCESS EXCLUSIVE sur chaque table sur laquelle il opère ", donc dans le premier bloc SQL que vous avez publié, tous les autres clients tentant d'accéder à la table après cette heure seront bloqués jusqu'à ce que vous ayezINSERT
terminé et toiCOMMIT
.Vous pouvez utiliser la même solution de contournement que dans votre code spécifique à MySQL; Postgres prend en charge à peu près la même syntaxe et aura un comportement de verrouillage similaire. En être témoin:
Bonus supplémentaire: Postgres prend en charge le DDL transactionnel, contrairement à MySQL, donc si vous devez ROLLBACK la transaction ci-dessus, vous pouvez le faire en toute sécurité.
la source
LOCK TABLE
méthode que vous avez suggérée, devrais-je la déverrouiller à nouveau avant leCOMMIT
, ou va-t-elle se déverrouiller elle-même?_old
-- LOCK TABLE "table" IN ROW EXCLUSIVE mode;
) semble insuffisant pour se protéger d'une mise à jour / insertion dans la table source selon les spécifications. DeuxROW EXCLUSIVE
verrous peuvent être acquis sans conflit (consultez le tableau 13.2 dans postgresql.org/docs/10/explicit-locking.html#LOCKING-TABLES ). Afin d'éviter les mises à jour des données, vous avez besoin d'au moins unSHARE
verrou.