it-swarm.com.de

Wie erkenne ich die Abfrage, die die Sperre in Postgres enthält?

Ich möchte ständig gegenseitige Sperren in Postgres verfolgen.

Ich bin auf Locks Monitoring article gestoßen und habe versucht, die folgende Abfrage auszuführen:

SELECT bl.pid     AS blocked_pid,
     a.usename  AS blocked_user,
     kl.pid     AS blocking_pid,
     ka.usename AS blocking_user,
     a.query    AS blocked_statement
FROM  pg_catalog.pg_locks         bl
 JOIN pg_catalog.pg_stat_activity a  ON a.pid = bl.pid
 JOIN pg_catalog.pg_locks         kl ON kl.transactionid = bl.transactionid AND kl.pid != bl.pid
 JOIN pg_catalog.pg_stat_activity ka ON ka.pid = kl.pid
WHERE NOT bl.granted;

Leider gibt es nie eine leere Ergebnismenge zurück. Wenn ich die angegebene Abfrage auf folgendes Formular vereinfache:

SELECT bl.pid     AS blocked_pid,
     a.usename  AS blocked_user,
     a.query    AS blocked_statement
FROM  pg_catalog.pg_locks         bl
 JOIN pg_catalog.pg_stat_activity a  ON a.pid = bl.pid
WHERE NOT bl.granted;

dann werden Abfragen zurückgegeben, die auf eine Sperre warten. Ich kann es jedoch nicht ändern, sodass blockierte und blockierende Abfragen zurückgegeben werden können.

Irgendwelche Ideen?

23
Roman

Seit 9.6 ist dies viel einfacher, da mit der Funktion pg_blocking_pids() die Sitzungen gefunden wurden, die eine andere Sitzung blockieren.

So kannst du so etwas verwenden:

select pid, 
       usename, 
       pg_blocking_pids(pid) as blocked_by, 
       query as blocked_query
from pg_stat_activity
where cardinality(pg_blocking_pids(pid)) > 0;
31

Aus diesem ausgezeichneten Artikel zu Abfragesperren in Postgres können blockierte Abfrage- und Blockerabfragen sowie deren Informationen aus der folgenden Abfrage abgerufen werden. 

CREATE VIEW lock_monitor AS(
SELECT
  COALESCE(blockingl.relation::regclass::text,blockingl.locktype) as locked_item,
  now() - blockeda.query_start AS waiting_duration, blockeda.pid AS blocked_pid,
  blockeda.query as blocked_query, blockedl.mode as blocked_mode,
  blockinga.pid AS blocking_pid, blockinga.query as blocking_query,
  blockingl.mode as blocking_mode
FROM pg_catalog.pg_locks blockedl
JOIN pg_stat_activity blockeda ON blockedl.pid = blockeda.pid
JOIN pg_catalog.pg_locks blockingl ON(
  ( (blockingl.transactionid=blockedl.transactionid) OR
  (blockingl.relation=blockedl.relation AND blockingl.locktype=blockedl.locktype)
  ) AND blockedl.pid != blockingl.pid)
JOIN pg_stat_activity blockinga ON blockingl.pid = blockinga.pid
  AND blockinga.datid = blockeda.datid
WHERE NOT blockedl.granted
AND blockinga.datname = current_database()
);

SELECT * from lock_monitor;

Da die Abfrage lang, aber nützlich ist, hat der Artikelautor eine Ansicht erstellt, um die Verwendung zu vereinfachen.

19
Devi

Eine Sache, die ich oft vermisse, ist die Fähigkeit, Reihenschlösser nachzuschlagen. Zumindest in den größeren Datenbanken, an denen ich gearbeitet habe, werden in pg_locks keine Zeilensperren angezeigt (wenn dies zutrifft, wären pg_locks viel, viel größer und es gibt keinen echten Datentyp, um die gesperrte Zeile in dieser Ansicht richtig anzuzeigen).

Ich weiß nicht, dass es eine einfache Lösung dafür gibt, aber normalerweise schaue ich in die Tabelle, in der die Sperre wartet, und suche nach Zeilen, in denen der Xmax-Wert unter der dort vorhandenen Transaktions-ID liegt. Das gibt mir normalerweise einen Startplatz, aber es ist ein bisschen praxisnah und nicht automatisierungsfreundlich.

Beachten Sie, dass in diesen Tabellen nicht festgeschriebene Schreibvorgänge für Zeilen angezeigt werden. Nach dem Festschreiben sind die Zeilen im aktuellen Snapshot nicht sichtbar. Aber für große Tische ist das ein Schmerz.

1
Chris Travers

Diese Änderung der Antwort von a_horse_with_no_name gibt Ihnen die Blockierungsabfragen zusätzlich zu den blockierten Sitzungen:

SELECT
    activity.pid,
    activity.usename,
    activity.query,
    blocking.pid AS blocking_id,
    blocking.query AS blocking_query
FROM pg_stat_activity AS activity
JOIN pg_stat_activity AS blocking ON blocking.pid = ANY(pg_blocking_pids(activity.pid));
0
jpmc26