dataiotech Labs
dbaguidedbaguideDBAdataxtoolsdataopsphere
PRODUCTION DIAGNOSTICS & OPERATIONAL SCRIPTS LIBRARY

100 Production DBA & SRE Diagnostic Scripts

Read-only diagnostic queries for PostgreSQL, MySQL, SQL Server, Oracle, and MongoDB covering lock chains, bloat, replication lag, cache hits, and bottleneck identification.

100 Verified Scripts
Read-Only Diagnostics
5 Database Engines
Showing: 1-10 of 100 scripts (Total: 100)
Page 1 of 10·ALL · ALL
#1
postgresql
Performance
read-onlyMin: 9.6

Find Long-Running Queries and Idle-in-Transaction Sessions in PostgreSQL

Lists queries running longer than a minute, their wait events, and idle-in-transaction sessions that block vacuum. The first script to run during a performance incident.

#pg_stat_activity#long-running#sessions#incident
sql
SELECT pid, usename, datname, state,
       now() - query_start AS query_age,
       now() - xact_start  AS xact_age,
       wait_event_type, wait_event,
       left(query, 200) AS query
FROM pg_stat_activity
WHERE pid <> pg_backend_pid()
  AND state <> 'idle'
  AND now() - query_start > interval '1 minute'
ORDER BY query_start;

Note: `idle in transaction` sessions block vacuum. To terminate them (write action), run `SELECT pg_cancel_backend(pid);`, or `pg_terminate_backend(pid)` if it does not respond.

Details & Share
#2
postgresql
Locking
read-onlyMin: 9.6

PostgreSQL Lock Chain: Who Is Blocking Whom?

Uses pg_blocking_pids to pair blocked and blocking sessions with their queries and wait times. Shows the root cause of a lock chain in seconds.

#locks#blocking#pg_blocking_pids#deadlock
sql
SELECT blocked.pid                AS blocked_pid,
       blocked.usename            AS blocked_user,
       left(blocked.query, 120)   AS blocked_query,
       blocker.pid                AS blocking_pid,
       blocker.usename            AS blocking_user,
       blocker.state              AS blocking_state,
       left(blocker.query, 120)   AS blocking_query,
       now() - blocked.query_start AS waiting_for
FROM pg_stat_activity blocked
JOIN LATERAL unnest(pg_blocking_pids(blocked.pid)) AS b(pid) ON true
JOIN pg_stat_activity blocker ON blocker.pid = b.pid
ORDER BY waiting_for DESC;

Note: The PID at the very top of the chain (not blocked by any other session) is the root cause blocker.

Details & Share
#3
postgresql
Maintenance
read-onlyMin: 9.4

PostgreSQL Dead Tuples, Bloat and Autovacuum Health Check

Shows dead tuple ratio and last vacuum/analyze times per table. Helps you find tables where autovacuum settings are not keeping up.

#vacuum#autovacuum#bloat#dead-tuples
sql
SELECT schemaname, relname,
       n_live_tup, n_dead_tup,
       round(100.0 * n_dead_tup / NULLIF(n_live_tup + n_dead_tup, 0), 2) AS dead_pct,
       last_vacuum, last_autovacuum, last_autoanalyze,
       pg_size_pretty(pg_total_relation_size(relid)) AS total_size
FROM pg_stat_user_tables
WHERE n_dead_tup > 10000
ORDER BY n_dead_tup DESC
LIMIT 30;

Note: If `dead_pct` is consistently above 20%, consider lowering `autovacuum_vacuum_scale_factor` for that specific table.

Details & Share
#4
postgresql
Performance
read-onlyMin: 9.2

Find Unused Indexes in PostgreSQL

Lists never-scanned indexes that are neither unique nor primary keys, with their sizes. Surfaces cleanup candidates to cut write overhead and disk usage.

#index#unused-index#pg_stat_user_indexes#cleanup
sql
SELECT s.schemaname, s.relname AS table_name, s.indexrelname AS index_name,
       s.idx_scan,
       pg_size_pretty(pg_relation_size(s.indexrelid)) AS index_size
FROM pg_stat_user_indexes s
JOIN pg_index i ON i.indexrelid = s.indexrelid
WHERE s.idx_scan = 0
  AND NOT i.indisunique
  AND NOT i.indisprimary
ORDER BY pg_relation_size(s.indexrelid) DESC
LIMIT 30;

Note: Statistics reflect usage since the last reset (`pg_stat_database.stats_reset`). Also check indexes used on replicas. Always drop with `DROP INDEX CONCURRENTLY`.

Details & Share
#5
postgresql
Performance
read-onlyMin: 13 (eski sürümde `total_time`, `mean_time`)

Top 20 Most Expensive PostgreSQL Queries with pg_stat_statements

Ranks queries by total time, call count and mean time. Tells you which query to tune first.

#pg_stat_statements#top-queries#tuning
sql
-- Gerekli: CREATE EXTENSION pg_stat_statements; (shared_preload_libraries)
SELECT round(total_exec_time::numeric, 0) AS total_ms,
       calls,
       round(mean_exec_time::numeric, 2)  AS mean_ms,
       round((100 * total_exec_time / sum(total_exec_time) OVER ())::numeric, 2) AS pct_total,
       rows,
       left(query, 150) AS query
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20;

Note: Verify in a staging environment prior to running in production. This is a read-only diagnostic query; it does not acquire exclusive locks.

Details & Share
#6
postgresql
Replication
read-onlyMin: 10

Measure PostgreSQL Streaming Replication Lag

Shows WAL lag in bytes and time on the primary, and replay delay on the standby. Used to monitor replication health and RPO risk.

#replication#lag#streaming#wal
sql
-- 1. Primary Üzerinde (Run on Primary)
SELECT application_name, client_addr, state, sync_state,
       pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn)) AS replay_lag_bytes,
       write_lag, flush_lag, replay_lag
FROM pg_stat_replication;

-- 2. Standby Üzerinde (Run on Standby)
SELECT now() - pg_last_xact_replay_timestamp() AS replay_delay;

Note: Verify in a staging environment prior to running in production. This is a read-only diagnostic query; it does not acquire exclusive locks.

Details & Share
#7
postgresql
Monitoring
read-onlyMin: 9.x

PostgreSQL Transaction ID Wraparound Risk Check

Shows XID age per database and how close it is to the wraparound limit. A reliable alert source to catch a critical outage early.

#xid#wraparound#freeze#critical
sql
SELECT datname,
       age(datfrozenxid) AS xid_age,
       round(100.0 * age(datfrozenxid) / 2147483647, 2) AS pct_to_wraparound
FROM pg_database
ORDER BY xid_age DESC;

Note: Aggressive vacuum triggers as transaction age approaches `autovacuum_freeze_max_age` (default 200M). Alert when utilization exceeds 50%.

Details & Share
#8
postgresql
Storage
read-onlyMin: 9.x

Largest Tables and Index Sizes in PostgreSQL

Ranks tables by table, index and total size with estimated row counts. Used for capacity planning and spotting partitioning candidates.

#table-size#capacity#pg_class#index-size
sql
SELECT n.nspname AS schema_name, c.relname AS table_name,
       pg_size_pretty(pg_total_relation_size(c.oid)) AS total_size,
       pg_size_pretty(pg_relation_size(c.oid))       AS table_size,
       pg_size_pretty(pg_indexes_size(c.oid))        AS index_size,
       c.reltuples::bigint AS est_rows
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r','m','p')
  AND n.nspname NOT IN ('pg_catalog','information_schema','pg_toast')
ORDER BY pg_total_relation_size(c.oid) DESC
LIMIT 25;

Note: `reltuples` is an estimate updated after `ANALYZE`.

Details & Share
#9
postgresql
Monitoring
read-onlyMin: 9.x

PostgreSQL Buffer Cache Hit Ratio

Computes the shared buffer hit ratio per database. Shows whether memory is undersized and whether too much data is read from disk.

#cache-hit#shared_buffers#pg_stat_database
sql
SELECT datname, blks_hit, blks_read,
       round(100.0 * blks_hit / NULLIF(blks_hit + blks_read, 0), 2) AS hit_pct
FROM pg_stat_database
WHERE datname IS NOT NULL
ORDER BY blks_read DESC;

Note: Expected to be above 99% in OLTP systems. Since the OS page cache also operates beneath PostgreSQL, interpret alongside `pg_stat_io` (PG 16+).

Details & Share
#10
postgresql
Performance
read-onlyMin: 9.x

PostgreSQL Tables with Heavy Sequential Scans

Finds tables that read many rows through sequential scans. A first step in identifying missing-index candidates.

#seq-scan#missing-index#pg_stat_user_tables
sql
SELECT schemaname, relname, seq_scan, seq_tup_read,
       idx_scan, n_live_tup,
       round(seq_tup_read::numeric / NULLIF(seq_scan, 0)) AS avg_rows_per_seq_scan
FROM pg_stat_user_tables
WHERE seq_scan > 0 AND n_live_tup > 10000
ORDER BY seq_tup_read DESC
LIMIT 20;

Note: Sequential scans on small tables are normal. Before adding an index, verify query execution plans using `EXPLAIN (ANALYZE, BUFFERS)`.

Details & Share