MVCC
Tout d'abord, si les "opérations normales" consistent en SELECT
requêtes, le modèle MVCC s'en chargera automatiquement. UPDATE
ne bloque pas SELECT
et vice versa. SELECT
ne voit que les données validées (ou ce qui a été fait dans la même transaction), donc le résultat du gros UPDATE
reste invisible pour les autres transactions jusqu'à ce qu'elle soit effectuée (validée).
Performance / ballonnement
Si vous n'avez pas d'autres objets faisant référence à cette table,
et vous n'avez pas d'opérations d'écriture simultanées (qui seraient perdues !),
et vous pouvez vous permettre un très court verrouillage exclusif sur la table,
et vous disposez de l'espace disque supplémentaire, bien sûr :
Vous pouvez limiter le verrouillage au minimum en créant une version mise à jour de la table en arrière-plan. Assurez-vous qu'il a tout pour être un remplacement direct, puis supprimez l'original et renommez le dupe.
CREATE TABLE tbl_new (LIKE tbl_org INCLUDING CONSTRAINTS);
INSERT INTO tbl_new
SELECT col_a, col_b, array[col] aS col_c
FROM tbl_org;
J'utilise CREATE TABLE (LIKE .. INCLUDING CONSTRAINTS)
, parce que (citant le manuel ici):
Les contraintes non nulles sont toujours copiées dans la nouvelle table.
CHECK
les contraintes ne seront copiées que siINCLUDING CONSTRAINTS
est spécifié ; les autres types de contraintes ne seront jamais copiés.
Assurez-vous que la nouvelle table est prête. Ensuite :
DROP tbl_org;
ALTER TABLE tbl_new RENAME TO tbl_org;
Résultats dans une fenêtre de temps très courte, où la table est verrouillée exclusivement.
Ce n'est vraiment qu'une question de performances. Il crée une nouvelle table sans ballonnement assez rapidement. Si vous avez des clés étrangères ou des vues, vous pouvez toujours suivre cette voie, mais vous devez préparer un script pour supprimer et recréer ces objets, créant potentiellement des verrous exclusifs supplémentaires.
Écritures simultanées
Avec les opérations d'écriture simultanées, tout ce que vous pouvez faire est de diviser votre mise à jour en morceaux. Vous ne pouvez pas faire cela en une seule transaction, car les verrous ne sont libérés qu'à la fin d'une transaction.
Vous pourriez employer dblink , qui peut lancer des transactions indépendantes sur une autre base de données, y compris elle-même. De cette façon, vous pouvez tout faire en un seul DO
instruction ou une fonction plpgsql avec une boucle. Voici une réponse vaguement liée avec plus d'informations sur dblink :
- Supprimer ou créer une base de données à partir d'une procédure stockée dans PostgreSQL
Votre approche avec les curseurs
Un curseur à l'intérieur de la fonction ne vous achètera rien . Toute fonction est automatiquement incluse dans une transaction et tous les verrous ne sont libérés qu'à la fin de la transaction. Même si vous avez utilisé le CLOSE cursor
(ce que vous ne faites pas) cela ne ferait que libérer quelques ressources, mais pas libérer les verrous acquis sur la table. Je cite le manuel :
CLOSE
ferme le portail sous-jacent à un curseur ouvert. Cela peut être utilisé pour libérer des ressources avant la fin de la transaction, ou pour libérer la variable de curseur pour qu'elle soit ouverte à nouveau.
Vous auriez besoin d'exécuter séparément opérations ou (ab)utilisez dblink qui le fait pour vous.