CodeGym /Kursy /SQL SELF /Monitorowanie blokad i konfliktów

Monitorowanie blokad i konfliktów

SQL SELF
Poziom 46, Lekcja 2
Dostępny

Wyobraź sobie, że pracujesz w biurze, gdzie wszystkie drzwi są zablokowane, bo ktoś zapomniał kluczy w środku pokoju. Tak właśnie działają blokady w PostgreSQL. Jeśli zapytanie albo transakcja zablokowała jakiś zasób, inne operacje próbujące dostać się do tego samego zasobu muszą poczekać, aż ta pierwsza się skończy. Taka sytuacja może powodować opóźnienia, konflikty i w skrajnym przypadku zatrzymać cały system.

Kiedy pojawiają się blokady?

Blokady (Locks) w PostgreSQL są używane do zarządzania współbieżnym dostępem do danych. Pojawiają się:

  1. Podczas operacji zapisu: UPDATE, DELETE, INSERT.
  2. Gdy transakcje trzymają zasób dłużej niż to potrzebne.
  3. Przy konfliktach między różnymi transakcjami, które chcą ten sam zasób.

Prawdziwa baza danych to "pole bitwy" o zasoby i nawet jeśli myślisz, że wszystko działa idealnie, jedna nieostrożna transakcja może wszystko "zablokować", jak nieudany merge w Git.

Narzędzia do analizy blokad: pg_locks

pg_locks to systemowy widok PostgreSQL pokazujący aktualne blokady trzymane i oczekiwane przez transakcje. Odpowiada na pytanie: "Kto trzyma blokadę, a kto czeka?"

Najważniejsze pola pg_locks:

  • locktype: typ blokady (np. relation, transaction, page, tuple).
  • database: identyfikator bazy danych.
  • relation: identyfikator tabeli (jeśli blokada dotyczy tabeli).
  • mode: tryb blokady (np. RowExclusiveLock, AccessShareLock).
  • granted: flaga pokazująca, czy blokada została przyznana (true), czy transakcja jeszcze na nią czeka (false).

Uwaga: PostgreSQL stosuje tzw. "hierarchiczny tryb blokad". To znaczy, że różne operacje mogą nakładać mniej restrykcyjne blokady (np. AccessShareLock do czytania danych) albo bardziej restrykcyjne (ExclusiveLock do zmiany struktury tabeli).

Przykład: podgląd wszystkich aktualnych blokad

SELECT *
FROM pg_locks;

Ale jeśli po prostu wyświetlisz całą zawartość pg_locks, będzie za dużo szumu. Spróbujmy czegoś bardziej sensownego!

Przykład: blokady, które jeszcze nie zostały przyznane (czyli transakcje czekają)

SELECT pid, locktype, relation::regclass AS table_name, mode, granted
FROM pg_locks
WHERE NOT granted;

Co tu się dzieje?

  • Filtrujemy rekordy, gdzie granted = false, czyli blokada jeszcze nie została przyznana.
  • relation::regclass zamienia identyfikator tabeli na jej nazwę, żeby było czytelniej.

Wynik może wyglądać mniej więcej tak:

pid locktype table_name mode granted
1234 relation students RowExclusiveLock false
4321 relation courses RowShareLock false

Te zapytania pomogą ci zidentyfikować, która tabela/zasób jest blokowana i która transakcja może być powodem.

Analiza konfliktów: pg_blocking_pids()

Blokady to jeszcze pół biedy, ale co zrobić, jeśli jedna transakcja blokuje drugą? PostgreSQL daje wygodny sposób na znalezienie "winowajcy" przez funkcję pg_blocking_pids().

Funkcja pg_blocking_pids() zwraca listę identyfikatorów procesów (pid), które blokują wykonanie aktualnej transakcji.

Przykład: szukanie transakcji, które blokują inne

SELECT pid, pg_blocking_pids(pid) AS blocking_pids
FROM pg_stat_activity
WHERE cardinality(pg_blocking_pids(pid)) > 0;

Co tu się dzieje?

  • Używamy widoku pg_stat_activity, żeby wyciągnąć aktywne procesy w systemie.
  • Funkcja pg_blocking_pids(pid) zwraca listę blokujących procesów dla każdego pid. Jeśli lista nie jest pusta (długość większa od 0), to znaczy, że proces jest zablokowany.

Przykład wyniku:

pid blocking_pids
4567 {1234, 5678}
6789 {4321}

Transakcja z pid = 4567 jest zablokowana przez procesy 1234 i 5678. Mamy naszych "winowajców".

Zakończenie blokujących procesów

Kiedy już znajdziesz blokujące procesy, możesz je zatrzymać przez funkcję pg_terminate_backend():

SELECT pg_terminate_backend(1234); -- "Zabijamy" proces 1234

Ale uważaj! Wymuszone zatrzymanie procesu może spowodować rollback danych w tej transakcji. Używaj tego narzędzia jak "atomowego przycisku" tylko w ostateczności.

Zastosowanie w praktyce: scenariusz analizy blokad

Załóżmy, że mamy bazę danych dla uniwersytetu z tabelami students i enrollments. Kilka transakcji próbuje jednocześnie zapisywać dane do tabeli enrollments i pojawiają się blokady.

  1. Identyfikacja blokad:
SELECT pid, locktype, relation::regclass AS table_name, mode, granted
FROM pg_locks
WHERE NOT granted;
  1. Określenie blokujących procesów:
SELECT pid, pg_blocking_pids(pid) AS blocking_pids
FROM pg_stat_activity
WHERE cardinality(pg_blocking_pids(pid)) > 0;
  1. Usuwanie blokad:

Wymuszamy zakończenie jednego z konfliktujących procesów:

SELECT pg_terminate_backend(1234); -- Kończymy proces 1234

Uwaga: Zanim "zabijesz" proces, spróbuj zrozumieć, dlaczego pojawiła się blokada. Może warto przejrzeć logikę transakcji.

Typowe błędy i jak ich unikać

Blokady często pojawiają się przez złe zarządzanie transakcjami. Na przykład:

Błąd: jedna transakcja trzyma blokadę zbyt długo, nie wykonując żadnych operacji (stan "idle in transaction").

Rozwiązanie: pilnuj stanu transakcji przez pg_stat_activity i kończ "zawieszone" transakcje.

SELECT pid, state, query
FROM pg_stat_activity
WHERE state = 'idle in transaction';

Błąd: zapomniałeś użyć indeksów w zapytaniach, co spowodowało blokady na całych tabelach.

Rozwiązanie: optymalizuj zapytania, dodając indeksy do często używanych warunków.

Wyświetlanie tabeli "kto na kogo czeka"

Dla wygody diagnostyki możesz zbudować drzewo zależności pokazujące, która transakcja blokuje którą:

WITH RECURSIVE blocking_tree AS (
  SELECT pid, pg_blocking_pids(pid) AS blocked_by
  FROM pg_stat_activity
  WHERE cardinality(pg_blocking_pids(pid)) > 0
  UNION ALL
  SELECT a.pid, pg_blocking_pids(a.pid)
  FROM pg_stat_activity a
  JOIN blocking_tree b ON a.pid = ANY(b.blocked_by)
)
SELECT pid, blocked_by FROM blocking_tree;

Wynik:

pid blocked_by
4567 {1234}
1234 {5678}
5678 {}

Widać tu, że proces 5678 blokuje proces 1234, a ten z kolei blokuje 4567.

2
Zadanie
SQL SELF, poziom 46, lekcja 2
Niedostępne
Pobieranie wszystkich aktualnych blokad w systemie
Pobieranie wszystkich aktualnych blokad w systemie
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION