Logo ← PostgreSQL Blog

PostgreSQL Emergency Kit: 10 SQL Queries to Save Your Production Database

When production is on fire, you don’t need a story :) you need working code. The following 10 queries aren’t fancy theories; they are…

PostgreSQL Emergency Kit: 10 SQL Queries to Save Your Production Database

When production is on fire, you don’t need a story :) you need working code. The following 10 queries aren’t fancy theories; they are battle-tested, refined SQL commands that deliver immediate results.

Table of Contents

  1. Deep Lock Analyzer: Who is blocking whom? (Recursive)
  2. Smart Size Inspector: Table vs Index Breakdown
  3. The Smart Sniper: Tiered Idle Connection Canceler (pg_cancel_backend)
  4. Mass Extinction: Force Kill Idle Sessions (pg_terminate_backend)
  5. Dead Tuple Detective: Bloat Check
  6. The Fixer: Manual Vacuum
  7. Unused Index Finder: Performance Tuning
  8. Active Queries Snapshot: Real-time Load
  9. Idle Duration Monitor: Who is sleeping?
  10. Cache Hit Ratio: Health Check

1. The Deep Lock Analyzer

Standard blocking queries often fail to show the full picture. This recursive query identifies the entire chain of dependency — showing exactly who is holding the lock and who started the traffic jam.

SELECT
        bl.pid      AS blocked_pid  ,
        ba.usename  AS blocked_user ,
        bl2.pid     AS blocking_pid ,
        ba2.usename AS blocking_user,
        ba.query    AS blocked_query,
        ba2.query   AS blocking_query
FROM
        pg_catalog.pg_locks bl JOIN pg_catalog.pg_stat_activity ba ON ba.pid = bl.pid JOIN pg_catalog.pg_locks bl2 ON ( bl.locktype = bl2.locktype
        AND bl.database IS NOT DISTINCT FROM bl2.database
        AND bl.relation IS NOT DISTINCT FROM bl2.relation
        AND bl.page IS NOT DISTINCT FROM bl2.page
        AND bl.tuple IS NOT DISTINCT FROM bl2.tuple
        AND bl.virtualxid IS NOT DISTINCT FROM bl2.virtualxid
        AND bl.transactionid IS NOT DISTINCT FROM bl2.transactionid
        AND bl.classid IS NOT DISTINCT FROM bl2.classid
        AND bl.objid IS NOT DISTINCT FROM bl2.objid
        AND bl.objsubid IS NOT DISTINCT FROM bl2.objsubid
        AND bl.pid <> bl2.pid ) JOIN pg_catalog.pg_stat_activity ba2 ON ba2.pid = bl2.pid
WHERE
        NOT bl.granted
AND     bl2.granted;

2. The Smart Size Inspector

When the disk alert fires, you need to know what is consuming space immediately. This query breaks down usage by Table Data vs. Index Data.

SELECT
        table_name                                                                                                       ,
        pg_size_pretty(pg_total_relation_size(quote_ident(table_schema) || '.' || quote_ident(table_name))) AS total_size,
        pg_size_pretty(pg_table_size(quote_ident(table_schema) || '.' || quote_ident(table_name)))          AS table_size,
        pg_size_pretty(pg_indexes_size(quote_ident(table_schema) || '.' || quote_ident(table_name)))        AS indexes_size
FROM
        information_schema.tables
WHERE
        table_schema = 'public' -- Change to your schema
ORDER BY
        pg_total_relation_size(quote_ident(table_schema) || '.' || quote_ident(table_name)) DESC;

3. The Smart Sniper (Soft Kill)

Action: pg_cancel_backend (Cancels query, keeps connection). This script uses tiered logic. It becomes more aggressive as the connection count rises. ( Connection numbers are only sample)

  • Low load (>450 conn): Cancels queries idle for >15 mins.
  • Critical load (>900 conn): Cancels queries idle for >3 mins.
WITH idle_connections AS
(
        SELECT
                pid,
                now() - state_change AS idle_duration
        FROM
                pg_stat_activity
        WHERE
                state   = 'idle'
        AND     datname = 'your_db_name' )
SELECT
        pg_cancel_backend(pid)
FROM
        idle_connections
WHERE
        (
                SELECT
                        count(*)
                FROM
                        idle_connections) > 450
AND     (
                (
                        (
                                SELECT
                                        count(*)
                                FROM
                                        idle_connections) > 900
                        AND idle_duration                 > interval '3 minutes')
                OR (
                        (
                                SELECT
                                        count(*)
                                FROM
                                        idle_connections) > 750
                        AND idle_duration                 > interval '5 minutes')
                OR (
                        (
                                SELECT
                                        count(*)
                                FROM
                                        idle_connections) > 600
                        AND idle_duration                 > interval '10 minutes')
                OR (
                        (
                                SELECT
                                        count(*)
                                FROM
                                        idle_connections) > 450
                        AND idle_duration                 > interval '15 minutes') );

4. Mass Extinction (Hard Kill)

Action: pg_terminate_backend (Terminates session/connection). Use this only when the pool is completely saturated and soft kill isn't enough.

SELECT
        pg_terminate_backend(pid)
FROM
        pg_stat_activity
WHERE
        state                = 'idle'
AND     now() - state_change > interval '20 minutes'
AND     datname              = 'your_db_name';

5. Dead Tuple Detective

Performance degrading slowly? Autovacuum might be failing. This identifies tables with the highest number of dead tuples (bloat).

SELECT
        relname    ,
        n_dead_tup ,
        n_live_tup ,
        last_vacuum,
        last_autovacuum
FROM
        pg_stat_all_tables
WHERE
        schemaname = '*****'
AND     n_dead_tup > 0
ORDER BY
        n_dead_tup DESC;

6. The Fixer (Manual Vacuum)

Don’t wait for the autovacuum scheduler. Run this manually to reclaim space immediately.

-- Replace with your schema.tablename
VACUUM VERBOSE ANALYZE public.target_table;

7. Unused Index Finder

Indexes speed up reads but slow down writes. An index with zero scans is technical debt.

SELECT
        schemaname  ,
        relname     ,
        indexrelname,
        idx_scan
FROM
        pg_stat_user_indexes
WHERE
        schemaname = '******'
AND     idx_scan   = 0
ORDER BY
        pg_relation_size(indexrelid) DESC;

8. Active Queries Snapshot

When CPU hits 100%, check what is running right now (excluding idle sessions).

SELECT
        pid                            ,
        usename                        ,
        application_name               ,
        client_addr                    ,
        now() - query_start as duration,
        state                          ,
        query
FROM
        pg_stat_activity
WHERE
        state != 'idle'
ORDER BY
        duration DESC;

9. Idle Duration Monitor

Inspect the “Sleepers” holding connections open without doing work.

SELECT
        pid                              ,
        usename                          ,
        application_name                 ,
        state                            ,
        now() - state_change as idle_time,
        query
FROM
        pg_stat_activity
WHERE
        state   = 'idle'
AND     datname = 'your_db_name'
ORDER BY
        idle_time DESC;

10. Cache Hit Ratio

Is your database running from RAM (fast) or Disk (slow)? Target should be 99%+.

SELECT
        sum(heap_blks_read)                                             as heap_read,
        sum(heap_blks_hit)                                              as heap_hit ,
        sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) as ratio
FROM
        pg_statio_user_tables;

Automate or Die

These queries are lifesavers for manual intervention. However, Engineer doesn’t watch a terminal all day.

If you want to visualize these metrics 24/7 and set up automatic alerts, check out my guide on Monitoring PostgreSQL Cluster: Server, Database and Logs.