DDL sicher mit lock_timeout und Wiederholungen anwenden (Lock Queues vermeiden)
PostgreSQLSessionsBefehl
-- Single attempt: give up if the lock is not acquired within 3 s instead of queueing and blocking traffic
SET lock_timeout = '3s';
ALTER TABLE customer ADD COLUMN IF NOT EXISTS segment text;
RESET lock_timeout;
-- Automatic retry: up to 5 attempts, 3 s apart
DO $$
DECLARE
attempt int := 0;
BEGIN
LOOP
attempt := attempt + 1;
BEGIN
SET LOCAL lock_timeout = '2s';
ALTER TABLE customer ADD COLUMN IF NOT EXISTS segment text;
RAISE NOTICE 'OK, attempt %', attempt;
EXIT;
EXCEPTION WHEN lock_not_available THEN
RAISE NOTICE 'lock not acquired, attempt %', attempt;
IF attempt >= 5 THEN RAISE; END IF;
PERFORM pg_sleep(3);
END;
END LOOP;
END $$;Was es tut
Verhindert, dass eine DDL, die ACCESS EXCLUSIVE braucht, endlos wartet, wenn sie die Sperre nicht bekommt, und dabei jede dahinter eingereihte Abfrage blockiert (Lock Queue); wiederholt den Versuch in kurzen Abständen.
Wann einsetzen
Beim Anwenden schneller, aber stark sperrender Änderungen wie ALTER TABLE, CREATE/DROP TRIGGER, ATTACH PARTITION oder RENAME auf stark genutzten Tabellen in der Produktion.
Vorsicht
Ohne lock_timeout lässt ein ALTER TABLE, das hinter einem einzigen langen SELECT wartet, auch jeden folgenden Lese-/Schreibzugriff warten und kann binnen Minuten den Connection Pool erschöpfen. lock_timeout begrenzt nur das Warten auf die Sperre, nicht die Laufzeit einer DDL, die die Tabelle neu schreibt (z. B. Änderung eines Spaltentyps). Der DO-Block ist eine einzige Transaktion und hält über alle Versuche hinweg einen Snapshot; für lange Wiederholungsszenarien besser eine externe Shell-Schleife verwenden.
Verwandte Einträge
- Backend beenden (pg_terminate_backend)
- Laufende Abfrage abbrechen (pg_cancel_backend)
- Aktive und blockierende Abfragen anzeigen
- Blockierungsbaum aufbauen (Root Blocker finden)
- Sperrwartezustände im Detail nach Objekt und Sperrmodus untersuchen (pg_locks)
- Lang laufende und 'idle in transaction'-Transaktionen finden