Part 6 · 2 chapters · ~12 min

Database-Side Diagnosis

Seeing the database's view of an incident: active sessions and wait events, the slowest queries right now, lock waits, plan changes after statistics updates, replication lag, connection counts by client, and correlating database sessions with application traces through application_name and query comments.

12

What the database sees right now

code
-- Postgres: what is running and what it waits on
SELECT pid, application_name, state, wait_event_type, wait_event, now() - query_start AS running, left(query, 80)
FROM pg_stat_activity WHERE state <> 'idle' ORDER BY running DESC;

-- who holds connections, by client
SELECT application_name, client_addr, state, count(*) FROM pg_stat_activity GROUP BY 1,2,3 ORDER BY 4 DESC;

-- MySQL equivalents
SELECT * FROM sys.processlist WHERE command <> 'Sleep' ORDER BY time DESC;
SELECT * FROM performance_schema.data_lock_waits;
wait event (Postgres)means
Lock: relation / tuple / transactionidwaiting on another session's lock
IO: DataFileReadreading pages from disk: working set beyond memory or a bad plan
LWLock: WALWrite, BufferContentinternal contention: heavy writes or hot pages
Client: ClientReadwaiting for the application (idle in transaction): an app bug
13

Correlating with application traces

code
-- tag every connection and query so the DB view points back to code
postgres://ledger@db/app?application_name=ledger-api-7f9c     (per pod or per service)
/* trace_id=4bf92f3577b34da6 route=POST_/transfers */ SELECT ...   -- sqlcommenter adds these automatically

With sqlcommenter (OpenTelemetry-compatible) every slow query in the database logs carries the trace id and route that issued it, and every span in the trace links to the exact query. Plan changes after an ANALYZE or a version upgrade show up as the same fingerprint suddenly slower in pg_stat_statements; auto_explain captures the new plan.