postgres locks LockManager - ghdrako/doc_snipets GitHub Wiki

Lock Level Blocks Reads? Blocks Writes? Acquired By
ACCESS SHARE No No SELECT
ROW SHARE No No SELECT FOR UPDATE/SHARE
ROW EXCLUSIVE No No INSERT, UPDATE, DELETE
SHARE UPDATE EXCLUSIVE No No VACUUM, CREATE INDEX CONCURRENTLY, ALTER TABLE (some)
SHARE No Yes CREATE INDEX (without CONCURRENTLY)
SHARE ROW EXCLUSIVE No Yes CREATE TRIGGER, some ALTER TABLE
EXCLUSIVE No Yes REFRESH MATERIALIZED VIEW CONCURRENTLY
ACCESS EXCLUSIVE Yes Yes DROP, TRUNCATE, most ALTER TABLE, VACUUM FULL, CLUSTER

The key insight: ACCESS EXCLUSIVE is the only lock that blocks reads. Everything else allows SELECT queries to continue. But anything from SHARE upward blocks writes (INSERT, UPDATE, DELETE)

Postgres Lock Types

  • ACCESS SHARE
  • ROW SHARE
  • ROW EXCLUSIVE
  • SHARE UPDATE EXCLUSIVE
  • SHARE
  • SHARE ROW EXCLUSIVE
  • EXCLUSIVE
  • ACCESS EXCLUSIVE

Share/Exclusive Types

  • ACCESS SHARE
  • ROW SHARE
  • ROW EXCLUSIVE
  • SHARE UPDATE EXCLUSIVE
  • SHARE
  • SHARE ROW EXCLUSIVE
  • EXCLUSIVE
  • ACCESS EXCLUSIV

Row/Access Types

  • ACCESS SHARE
  • ROW SHARE
  • ROW EXCLUSIVE
  • SHARE UPDATE EXCLUSIVE
  • SHARE
  • SHARE ROW EXCLUSIVE
  • EXCLUSIVE
  • ACCESS EXCLUSIVE

Lock Maager PG18+

  • Struktura zarządzania blokadami jest teraz bardziej rozproszona (sharded / partitioned).
  • Zamiast jednej globalnej blokady LockMgrLock, istnieje wiele segmentów (partitioned lock tables), co pozwala na równoległy dostęp.
  • Dzięki temu eliminuje się “contention”, czyli wzajemne blokowanie się procesów przy próbie zapisu do wspólnej struktury.
  • To oznacza, że wielowątkowe / wielosesyjne obciążenia (np. OLTP, duże batch insert/update, równoległe DDL) działają teraz znacznie szybciej i płynniej.

Lock Manager

  • W PostgreSQL wszystkie blokady (np. na tabele, indeksy, relacje itp.) są zarządzane przez centralny Lock Manager.
  • Jest on zabezpieczony przez lekkie blokady wewnętrzne (Lightweight Locks, czyli LWLock), aby zapewnić synchronizację dostępu wielu procesów.
  • przy duzej liczbie blokad staje sie waski gardlem co ie objawia:
    • widoczny w pg_stat_activity lub perf jako:
SELECT * FROM pg_stat_activity WHERE wait_event = 'LWLock:LockManager';
LWLock:LockManager
  • albo logi typu:
LOG:  process 12345 still waiting for LockManager

Co powoduje presje i contension na LockManager

  • duza liczba indeksow
  • partycje
  • duze zrownoleglenie - wiele tranzakcji, zapytan
  • wymuszenie planów generycznych (aby plan nie był rekalkulowany co zapytanie) może pogorszyć sytuację w kontekście LockManagera, bo może wymagać bardziej ogólnych mechanizmów blokad Jak przeciwdzialac:
  • zmniejszenie liczby indeksów,
  • przemyślane partycje (mniej, większe partie zamiast wielu codziennych),
  • użycie planów przygotowanych/ unikanie ponownego planowania, ewentualne zmiany w kodzie PostgreSQL (patchy dotyczące LWLock)

max_locks_per_transaction

Parametr max_locks_per_transaction określa, ile jednostek blokad (lock entries) może posiadać jedna transakcja. Gdy za maly to blad:

ERROR: out of shared memory
HINT: You might need to increase max_locks_per_transaction.

Podnoszenie max_locks_per_transaction pogarsza performance.