web-dev-qa-db-fra.com

Comment libérer d'éventuels verrous de ligne Postgres?

J'ai exécuté une déclaration de mise à jour sur une grande table PostgreSQL via l'interface phpPgAdmin. Cela a expiré car il a fonctionné trop longtemps.

Je peux maintenant mettre à jour certaines lignes de cette table mais pas toutes. Toute tentative de mise à jour de certaines lignes se bloquera.

Les rangées sont-elles verrouillées? Comment puis-je autoriser la mise à jour de ces lignes?

34
Liam

Quelle version de PostgreSQL utilisez-vous? Ce qui suit suppose la version 8.1.8 ou ultérieure (cela peut également s'appliquer aux versions antérieures, je ne sais pas).

Je suppose que vous voulez dire que phpPgAdmin a expiré - le backend PostgreSQL prendra aussi longtemps qu'il le faudra pour terminer 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 (tirée de chapitre 24 des documents PostgreSQL ) sur la machine qui héberge le processus du 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 pour les processus "écrivain", "tampon statistiques" et "collecteur de statistiques". Toutes les lignes restantes sont destinées aux processus desservant des connexions DB. Ces lignes contiendront le nom d'utilisateur et le nom de la base de données.

J'espère que vous pourrez voir si la session dans laquelle vous avez effectué la mise à jour d'origine est toujours en suspens. Bien qu'en théorie, vous puissiez trouver des informations plus détaillées en SELECTing à partir de 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 l'activer à l'avenir.

Si vous voyez que la session est toujours là, tuez-la. Vous devrez être connecté en tant qu'utilisateur exécutant le processus (généralement postgres) ou root pour le faire - si vous n'exécutez pas le serveur vous-même, demandez à votre DBA de le faire pour vous.

Encore une chose: pour mettre à jour les lignes d'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 base de données, qui devient la "version actuelle" lorsque la transaction est validée, à condition qu'elle n'entre pas en conflit avec les mises à jour effectuées entre-temps par d'autres transactions. Je soupçonne donc que la "pendaison" que vous voyez est causée par autre chose - mais quoi, je ne suis pas sûr. (Avez-vous vérifié les éléments évidents, par exemple si la partition de disque contenant la base de données est pleine?)

21
j_random_hacker

Il est possible de voir les serrures.

Voici une vue pour le rendre un peu plus facile que d'utiliser directement pg_locks:

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, il vous suffit de sélectionner dans la vue:

SELECT * FROM active_locks;

Et tuez-le avec:

SELECT pg_cancel_backend('%pid%');

Autres solutions: http://wiki.postgresql.org/wiki/Lock_Monitoring

77
Chris

Simple:

Obtenez les verrous actifs de pg_locks:

sélectionnez t.relname, l.locktype, page, virtualtransaction, pid, mode, accordé à partir de pg_locks l, pg_stat_all_tables t où l.relation = t.relid ordre par relation asc;

Copiez le pid (ex: 14210) du résultat ci-dessus et remplacez-le dans la commande ci-dessous.

SELECT pg_terminate_backend ('14210')

16
chiru

Pour libérer d'éventuels verrous de Postgres, je les suit généralement dans l'ordre.

  1. Recherchez des requêtes de longue durée dans votre base de données en exécutant la requête suivante. Cela vous aidera à récupérer les PID de la requête de longue durée qui bloque votre mise à jour.

    SELECT
    pid,
    now() - pg_stat_activity.query_start AS duration,
    query,
    state
    FROM pg_stat_activity
    WHERE (now() - pg_stat_activity.query_start) > interval '5 minutes';
    
  2. ou si vous pouvez savoir quels processus détiennent un verrou sur une table particulière en exécutant cette requête

    SELECT *
    FROM pg_locks l
    JOIN pg_class t ON l.relation = t.oid AND t.relkind = 'r'
    WHERE t.relname = 'Bill';
    
  3. Une fois que vous avez déterminé le PID qui est "actif" et que vous avez bloqué votre mise à jour, vous pouvez le tuer en exécutant cette requête. Il faut un certain temps pour tuer le processus.

    SELECT pg_cancel_backend(__pid__);
    
  4. Vérifiez en exécutant la requête 2 si le processus est interrompu. S'il est toujours actif, supprimez ce processus en exécutant cette requête.

    SELECT pg_terminate_backend(__pid__);
    
4
Saurabh Saha