Skip to content

Instantly share code, notes, and snippets.

@webdestroya
Last active May 23, 2023 04:54
Show Gist options
  • Save webdestroya/aaa75c508218c4586777bce393037631 to your computer and use it in GitHub Desktop.
Save webdestroya/aaa75c508218c4586777bce393037631 to your computer and use it in GitHub Desktop.
Postgres commands for debugging

Process List

SELECT (NOW() - query_start) as duration, pid, usename, application_name, client_addr, client_port, backend_start, query_start,
wait_event, wait_event_type, state, query
FROM pg_stat_activity 
WHERE pid <> pg_backend_pid()
AND state <> 'idle'
ORDER BY query_start ASC;

Long running queries

SELECT (NOW() - query_start) as duration, pid, usename, application_name, client_addr, client_port, backend_start, query_start,
wait_event, wait_event_type, state, query
FROM pg_stat_activity 
WHERE pid <> pg_backend_pid()
AND state <> 'idle'
AND age(now(),pg_stat_activity.query_start) > '00:05:00'
ORDER BY query_start ASC

Killing long running queries

SELECT 
pg_cancel_backend(pid),
(NOW() - query_start) as duration, pid, usename, application_name, client_addr, client_port, backend_start, query_start,
wait_event, wait_event_type, state, query
FROM pg_stat_activity 
WHERE pid <> pg_backend_pid()
AND state <> 'idle'
AND age(now(),pg_stat_activity.query_start) > '00:10:00'
ORDER BY query_start ASC

-- https://github.com/heroku/heroku-pg-extras/tree/master/commands
-- violent: pg_terminate_backend / pg_cancel_backend

Locks

SELECT
    pg_stat_activity.pid,
    pg_class.relname,
    pg_locks.transactionid,
    pg_locks.granted,
    pg_stat_activity.query AS query_snippet,
    age(now(),pg_stat_activity.query_start) AS "age"
  FROM pg_stat_activity,pg_locks left
  OUTER JOIN pg_class
    ON (pg_locks.relation = pg_class.oid)
  WHERE pg_stat_activity.query <> '<insufficient privilege>'
    AND pg_locks.pid = pg_stat_activity.pid
    AND pg_locks.mode = 'ExclusiveLock'
    AND pg_stat_activity.pid <> pg_backend_pid() order by query_start;

Blocking Queries

SELECT bl.pid AS blocked_pid,
  ka.query AS blocking_statement,
  now() - ka.query_start AS blocking_duration,
  kl.pid AS blocking_pid,
  a.query AS blocked_statement,
  now() - a.query_start AS blocked_duration
FROM pg_catalog.pg_locks bl
JOIN pg_catalog.pg_stat_activity a
  ON bl.pid = a.pid
JOIN pg_catalog.pg_locks kl
  JOIN pg_catalog.pg_stat_activity ka
    ON kl.pid = ka.pid
ON bl.transactionid = kl.transactionid AND bl.pid != kl.pid
WHERE NOT bl.granted

Vacuum Progress

SELECT vs.pid, tbl.relname, vs.phase, vs.heap_blks_total, vs.heap_blks_scanned, vs.heap_blks_vacuumed, vs.index_vacuum_count, vs.max_dead_tuples, vs.num_dead_tuples,
tbl.last_autovacuum, tbl.autovacuum_count
FROM pg_stat_progress_vacuum vs
INNER JOIN pg_stat_all_tables tbl ON tbl.relid=vs.relid

Blocks

SELECT blocked_locks.pid     AS blocked_pid,
        blocked_activity.usename  AS blocked_user,
        blocking_locks.pid     AS blocking_pid,
        blocking_activity.usename AS blocking_user,
        blocked_activity.query    AS blocked_statement,
        blocking_activity.query   AS current_statement_in_blocking_process
  FROM  pg_catalog.pg_locks         blocked_locks
   JOIN pg_catalog.pg_stat_activity blocked_activity  ON blocked_activity.pid = blocked_locks.pid
   JOIN pg_catalog.pg_locks         blocking_locks
       ON blocking_locks.locktype = blocked_locks.locktype
       AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
       AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
       AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
       AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
       AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
       AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
       AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
       AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
       AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
       AND blocking_locks.pid != blocked_locks.pid
   JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
  WHERE NOT blocked_locks.GRANTED;

Expensive Queries

SELECT * 
FROM pg_stat_statements
WHERE calls >= 5 
ORDER BY mean_time DESC
LIMIT 100

Index Size/Usage

SELECT
    t.tablename,
    indexname,
    c.reltuples AS num_rows,
    pg_size_pretty(pg_relation_size(quote_ident(t.tablename)::text)) AS table_size,
    pg_size_pretty(pg_relation_size(quote_ident(indexrelname)::text)) AS index_size,
    CASE WHEN indisunique THEN 'Y'
       ELSE 'N'
    END AS UNIQUE,
    idx_scan AS number_of_scans,
    idx_tup_read AS tuples_read,
    idx_tup_fetch AS tuples_fetched
FROM pg_tables t
LEFT OUTER JOIN pg_class c ON t.tablename=c.relname
LEFT OUTER JOIN
    ( SELECT c.relname AS ctablename, ipg.relname AS indexname, x.indnatts AS number_of_columns, idx_scan, idx_tup_read, idx_tup_fetch, indexrelname, indisunique FROM pg_index x
           JOIN pg_class c ON c.oid = x.indrelid
           JOIN pg_class ipg ON ipg.oid = x.indexrelid
           JOIN pg_stat_all_indexes psai ON x.indexrelid = psai.indexrelid )
    AS foo
    ON t.tablename = foo.ctablename
WHERE t.schemaname='public'
ORDER BY 1,2;

Non-unique index usage

SELECT
    t.tablename,
    indexname,
    c.reltuples AS num_rows,
    pg_size_pretty(pg_relation_size(quote_ident(t.tablename)::text)) AS table_size,
    pg_size_pretty(pg_relation_size(quote_ident(indexrelname)::text)) AS index_size,
    idx_scan AS number_of_scans,
    idx_tup_read AS tuples_read,
    idx_tup_fetch AS tuples_fetched
FROM pg_tables t
LEFT OUTER JOIN pg_class c ON t.tablename=c.relname
LEFT OUTER JOIN
    ( SELECT c.relname AS ctablename, ipg.relname AS indexname, x.indnatts AS number_of_columns, idx_scan, idx_tup_read, idx_tup_fetch, indexrelname, indisunique FROM pg_index x
           JOIN pg_class c ON c.oid = x.indrelid
           JOIN pg_class ipg ON ipg.oid = x.indexrelid
           JOIN pg_stat_all_indexes psai ON x.indexrelid = psai.indexrelid )
    AS foo
    ON t.tablename = foo.ctablename
WHERE t.schemaname='public' AND NOT indisunique
ORDER BY 1,2;

Replication

-- show logical replication slots
SELECT * FROM pg_replication_slots;

-- Drop bad replication slot
select pg_drop_replication_slot('w65jlk5x6jyxkpou_00016401_60187b16_5cb2_4d11_b756_7dc72e5dd5a6')

AutoVac

-- Disable AutoVac
ALTER TABLE investments SET (autovacuum_enabled = false, toast.autovacuum_enabled = false);

-- reenable
ALTER TABLE investments SET (autovacuum_enabled = true, toast.autovacuum_enabled = true);

Data Size

SELECT nspname || '.' || relname AS "relation",
    pg_size_pretty(pg_relation_size(C.oid)) AS "size"
  FROM pg_class C
  LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
  WHERE nspname NOT IN ('pg_catalog', 'information_schema')
  ORDER BY pg_relation_size(C.oid) DESC
  LIMIT 20;

Table Size

SELECT nspname || '.' || relname AS "relation",
  pg_size_pretty(pg_relation_size(C.oid)) AS "size"
FROM pg_class C
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE nspname NOT IN ('pg_catalog', 'information_schema')
AND relname IN ('TABLE_NAME')
ORDER BY pg_relation_size(C.oid) DESC
LIMIT 100;

Wraparound vac "todo list"

SELECT
       oid::regclass::text AS table,
       age(relfrozenxid) AS xid_age, 
       mxid_age(relminmxid) AS mxid_age, 
       least( 
(SELECT setting::bigint
            FROM    pg_settings
            WHERE   name = 'autovacuum_freeze_max_age') - age(relfrozenxid), 
(SELECT setting::bigint
            FROM    pg_settings
            WHERE   name = 'autovacuum_multixact_freeze_max_age') - mxid_age(relminmxid)  
) AS tx_before_wraparound_vacuum,
pg_size_pretty(pg_total_relation_size(oid)) AS size,
pg_stat_get_last_autovacuum_time(oid) AS last_autovacuum
FROM    pg_class
WHERE   relfrozenxid != 0
AND oid > 16384
ORDER BY tx_before_wraparound_vacuum;

Misc

-- show options
SELECT relname, reloptions FROM pg_class;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment