$ lexprog.com

// notes from an old coder -- php, databases, and the occasional rant

[March 16, 2025] PostgreSQL

PostgreSQL Advisory Locks: Application-Level Locking

PostgreSQL Advisory Locks: Application-Level Locking

────────────────────────────────────────────────────────

PostgreSQL Advisory Locks: Application-Level Locking

Tip: Session-Level Advisory Lock

SELECT pg_advisory_lock(12345);
-- Critical section
SELECT pg_advisory_unlock(12345);

Lock is released when the session ends.

Gotcha: Transaction-Level Locks

SELECT pg_advisory_xact_lock(12345);

Automatically released at transaction end. No need to unlock.

Tip: Try Lock (Non-Blocking)

SELECT pg_try_advisory_lock(12345);

Returns true if acquired, false if already locked.

Gotcha: Lock IDs Are Integers

Use a hash function to convert strings to lock IDs:

SELECT pg_advisory_lock(hashtext('my_resource_name'));

Tip: Laravel Integration

DB::select('SELECT pg_try_advisory_lock(?)', [crc32('report-generation')]);

Gotcha: Advisory Locks Are Per-Connection

Each database connection has its own lock namespace. Locks don't work across connections with the same ID.

Tip: EXPLAIN (ANALYZE, BUFFERS) Is Your Best Friend

For query debugging, always use EXPLAIN (ANALYZE, BUFFERS) instead of plain EXPLAIN. The BUFFERS option shows hit/miss rates for every node, revealing whether your indexes are actually in memory.

Tip: Partial Indexes Are Underutilized

CREATE INDEX ON orders (status) WHERE status = 'pending' creates a tiny index that covers only the rows your query needs. It's faster to scan and cheaper to maintain than a full-column index.

Gotcha: NULL Sorting Is Non-Obvious

By default, NULLs sort AFTER non-null values in ascending order. ORDER BY col DESC puts NULLs FIRST. Use NULLS LAST or NULLS FIRST to be explicit.

Senior Insight

PostgreSQL advisory locks are application-level locks managed by the database. I've used them as a distributed locking mechanism for Laravel scheduled tasks running across multiple servers, avoiding the need for Redis just for mutexes. The critical detail: advisory locks are not automatically released on transaction commit — they're session-level. Always release advisory locks explicitly in a finally block, or use the pg_advisory_xact_lock() variant that releases on transaction end.

Source: pganalyze Blog (https://pganalyze.com/blog), PostgreSQL Docs (https://www.postgresql.org/docs/current/), Crunchy Data Blog (https://www.crunchydata.com/blog)

────────────────────────────────────────────────────────
<-- back to posts