PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Mise à jour des lignes de la base de données sans verrouiller la table dans PostgreSQL 9.2

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 si INCLUDING 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.