2009-06-30 4 views
21

J'ai exécuté une instruction de mise à jour sur une grande table PostgreSQL via l'interface phpPgAdmin. Cela a expiré car il a duré trop longtemps.Comment libérer d'éventuels verrous Row de Postgres?

Je peux maintenant mettre à jour certaines lignes de cette table mais pas toutes. Essayer de mettre à jour certaines lignes va se bloquer.

Les lignes sont-elles verrouillées? Comment puis-je autoriser ces lignes à être mises à jour?

Répondre

20

Quelle version de PostgreSQL utilisez-vous? Ce qui suit suppose 8.1.8 ou plus tard (il peut aussi s'appliquer aux versions antérieures, je ne sais pas).

Je suppose que vous voulez dire que phpPgAdmin a expiré - le backend PostgreSQL prendra autant de temps que nécessaire pour compléter une requête/mise à jour. Dans ce cas, il est possible que la session d'origine soit toujours active et que la requête UPDATE soit toujours en cours d'exécution. Je suggère d'exécuter la requête suivante (extrait de chapter 24 of the PostgreSQL docs) sur la machine qui héberge le processus serveur PostgreSQL, pour voir si la session est toujours en vie:

ps auxwww|grep ^postgres 

Plusieurs lignes doivent apparaître: 1 pour le processus maître postmaster et 1 chacun pour les processus "writer", "stats buffer" et "stats collector". Les lignes restantes sont destinées aux processus servant les connexions DB. Ces lignes contiendront le nom d'utilisateur et le nom de la base de données.

Espérons que vous puissiez voir si la session dans laquelle vous avez effectué la mise à jour d'origine est encore en cours. Bien qu'en théorie vous puissiez trouver des informations plus détaillées par SELECT depuis la vue système pg_stat_activity, par défaut PostgreSQL n'est pas configuré pour remplir les champs les plus utiles (tels que current_query et query_start). Voir le chapitre 24 pour savoir comment activer cela dans le futur.

Si vous voyez que la session est toujours là, tuez-la. Vous devez être connecté en tant qu'utilisateur exécutant le processus (généralement postgres) ou en tant que root pour le faire - si vous n'exécutez pas le serveur vous-même, demandez à votre administrateur de base de données de le faire pour vous. Une autre chose: pour mettre à jour des lignes dans une table, PostgreSQL évite d'utiliser des verrous. Au lieu de cela, il permet à chaque transaction d'écriture de créer une nouvelle «version» de la BD, qui devient la «version actuelle» lorsque la transaction est validée, à condition qu'elle ne soit pas en conflit avec les mises à jour effectuées par d'autres transactions. Donc je soupçonne que la "pendaison" que vous voyez est causée par quelque chose d'autre - mais quoi, je ne suis pas sûr. (Avez-vous vérifié les choses évidentes, comme si la partition de disque contenant le DB est pleine?)

+0

Excellent, cela a fonctionné, merci. Notez que lorsque j'ai tué le processus à l'origine du problème, cela a permis à d'autres processus de s'exécuter qui attendaient la libération du verrou. Cela a causé d'autres problèmes. J'aurais dû tuer les processus marqués "WAITING" quand j'ai couru ps auxwww | grep^postgres avant de tuer le premier processus de problème. – Liam

+0

Je suis heureux d'avoir pu aider :) –

+2

"Si vous voyez que la session est toujours là, tuez-la." - Pour les débutants, regardez où il est écrit 'postgres 15398 ... idle in transaction' ou quoi que ce soit et tapez' kill 15398' dans Putty. – Noumenon

0

Je n'ai jamais travaillé avec PostreSql mais si c'est similaire à d'autres, je dirais que vous devez tuer la connexion/mettre fin à la transaction qui détient les verrous.

46

Il est possible de voir les verrous.

est ici en vue de le rendre un peu plus facile que d'utiliser pg_locks directement:

CREATE OR REPLACE VIEW public.active_locks AS 
SELECT t.schemaname, 
    t.relname, 
    l.locktype, 
    l.page, 
    l.virtualtransaction, 
    l.pid, 
    l.mode, 
    l.granted 
    FROM pg_locks l 
    JOIN pg_stat_all_tables t ON l.relation = t.relid 
    WHERE t.schemaname <> 'pg_toast'::name AND t.schemaname <> 'pg_catalog'::name 
    ORDER BY t.schemaname, t.relname; 

Ensuite, vous sélectionnez simplement de la vue:

SELECT * FROM active_locks; 

et tuez-le avec:

SELECT pg_cancel_backend('%pid%'); 
Autres solutions: http://wiki.postgresql.org/wiki/Lock_Monitoring
+2

Il n'y a pas de vue ou de table avec le nom 'active_locks' dans Postgres. Voulez-vous dire 'pg_locks'? –

+0

Vous avez raison, il y avait une vue personnalisée dans notre base de données, j'ai édité la réponse. – Chris

+0

Dans mon cas, votre 'pg_cancel_backend' en combinaison avec le qeury ici: http://stackoverflow.com/a/10317371/301277 m'a permis d'enlever tous les verrous" oubliés ". Merci! –