Skip to main content
View rawEdit

13. Lock contention analysis

Monitor lock waits and identify blocking chains.

13. Lock contention dashboard

Screenshot note

This dashboard only shows data when lock contention is occurring. In low-contention environments, panels will be empty. This is expected behavior — an empty dashboard indicates healthy lock performance.

Purpose​

Diagnose lock-related performance issues:

  • Identify blocking queries
  • Find lock contention hotspots
  • Analyze deadlock patterns
  • Plan maintenance windows

When to use​

  • Applications experiencing lock timeout errors
  • Queries waiting unexpectedly
  • During DDL operations
  • Investigating deadlocks

Key panels​

Lock waits over time​

What it shows:

  • Number of sessions waiting for locks
  • Lock wait duration distribution

Warning signs:

  • Sustained lock waits
  • Increasing wait times
  • Correlation with specific operations

Blocking chains​

What it shows:

  • Which sessions are blocking others
  • Depth of blocking chains

Interpretation:

  • Single blocker affecting many — address that query
  • Deep chains — potential design issue

Locks by type​

What it shows:

  • Distribution of lock types
  • Most common contention points
Lock typeDescriptionCommon cause
RowExclusiveLockRow modificationsUPDATE/DELETE conflicts
AccessShareLockSELECT operationsLong-running queries
AccessExclusiveLockDDL operationsALTER TABLE, DROP
ShareLockIndex creationCREATE INDEX

Lock wait duration​

What it shows:

  • How long queries wait for locks
  • Percentile distribution

Variables​

VariablePurpose
cluster_nameCluster filter
node_nameNode filter
db_nameDatabase filter

Lock analysis queries​

Current lock waits​

select
blocked.pid as blocked_pid,
blocked.query as blocked_query,
blocking.pid as blocking_pid,
blocking.query as blocking_query,
now() - blocked.query_start as wait_duration
from pg_stat_activity as blocked
join pg_locks as blocked_locks
on blocked.pid = blocked_locks.pid
join pg_locks as blocking_locks
on blocked_locks.locktype = blocking_locks.locktype
and blocked_locks.database is not distinct from blocking_locks.database
and blocked_locks.relation is not distinct from blocking_locks.relation
and blocked_locks.page is not distinct from blocking_locks.page
and blocked_locks.tuple is not distinct from blocking_locks.tuple
and blocked_locks.virtualxid is not distinct from blocking_locks.virtualxid
and blocked_locks.transactionid is not distinct from blocking_locks.transactionid
and blocked_locks.classid is not distinct from blocking_locks.classid
and blocked_locks.objid is not distinct from blocking_locks.objid
and blocked_locks.objsubid is not distinct from blocking_locks.objsubid
and blocked_locks.pid != blocking_locks.pid
join pg_stat_activity as blocking
on blocking_locks.pid = blocking.pid
where not blocked_locks.granted
order by wait_duration desc;

Lock statistics by table​

select
relname,
mode,
granted,
count(*)
from pg_locks l
join pg_class c on l.relation = c.oid
where relnamespace = 'public'::regnamespace
group by relname, mode, granted
order by count(*) desc;

Recent deadlocks​

Check PostgreSQL logs for deadlock entries, or use:

select
datname,
deadlocks
from pg_stat_database
where deadlocks > 0;

Resolving lock issues​

Immediate actions​

  1. Identify the blocker:

    select pid, query, state, wait_event
    from pg_stat_activity
    where pid in (select pid from pg_locks where not granted);
  2. Terminate if necessary:

    select pg_terminate_backend(blocking_pid);

Preventive measures​

IssueSolution
Long transactionsSet idle_in_transaction_session_timeout
DDL during trafficUse lock_timeout, schedule maintenance
Hot row contentionReview application design
DeadlocksConsistent lock ordering in application

Troubleshooting​

No lock data shown​

  1. Verify there are actual lock waits occurring
  2. Check time range — lock waits may be brief

Frequent deadlocks​

  1. Review application transaction patterns
  2. Ensure consistent lock ordering
  3. Consider advisory locks for complex scenarios
  4. Check for missing indexes causing full table locks