Skip to content
10 Actually Useful PostgreSQL Commands (2026)

10 Actually Useful PostgreSQL Commands (2026)

DodaTech Updated Jun 20, 2026 4 min read

You know SELECT, INSERT, and CREATE TABLE. This list targets the commands that database administrators and performance engineers use daily — debugging slow queries, managing connections, inspecting bloat, and safely migrating schemas on production systems. Every command here solves a problem you don’t know you have until 2 AM.

Performance & Debugging

EXPLAIN ANALYZE — Executes a query and shows the actual execution plan with timings. The single most important tool for query optimization. Add BUFFERS to see cache hit ratios.

EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) SELECT * FROM orders WHERE status = 'pending';

Output: Shows sequential scan vs index scan, actual vs estimated rows, execution time per node, and buffer usage. Look for “Seq Scan on large_table” with high rows removed by filter — that’s your missing index.

pg_stat_statements — Tracks execution statistics for every query. Find your top time-consuming queries, most frequent ones, and worst cache misses.

SELECT query, calls, total_exec_time, mean_exec_time, rows
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;

Output: The top 10 queries by total execution time. Mean time under 1ms is good. High calls + high mean time is your biggest optimization opportunity.

pg_terminate_backend — Kills a specific database connection by its PID. Essential when a query won’t cancel, a connection is stuck, or you need to drop a database that has active connections.

SELECT pg_terminate_backend(pid) FROM pg_stat_activity
WHERE state = 'idle in transaction' AND age(now(), state_change) > interval '1 hour';

Output: Terminates all idle transactions older than one hour. Run this before DROP DATABASE to disconnect everyone.

Maintenance

Table Bloat Check — Estimates wasted space in tables and indexes. PostgreSQL’s MVCC creates dead tuples that VACUUM cleans, but bloat accumulates.

SELECT schemaname, tablename,
  n_dead_tup, n_live_tup,
  round(n_dead_tup * 100.0 / nullif(n_live_tup + n_dead_tup, 0), 2) AS dead_pct
FROM pg_stat_user_tables
WHERE n_dead_tup > 10000
ORDER BY n_dead_tup DESC;

Output: Tables with high dead tuple counts. Above 20% dead ratio means VACUUM is falling behind — check autovacuum settings.

VACUUM and ANALYZE — VACUUM reclaims storage from dead tuples. ANALYZE updates query planner statistics. Run them together weekly on production.

VACUUM (ANALYZE, VERBOSE) your_table;

Output: Shows pages removed, tuples deleted, and new statistics. VERBOSE helps you see actual progress. Never run VACUUM FULL on production — it locks the table.

pg_ls_waldir — Lists Write-Ahead Log (WAL) files. WAL accumulation causes disk-full disasters. If WAL files exceed a few GB, check replication lag or archive failures.

SELECT count(*), sum(size) / 1048576 AS total_mb
FROM pg_ls_waldir();

Output: Total WAL size in MB. 1-2 GB is normal for active systems. 10+ GB means WAL archiving or replication is broken.

Schema & Data Management

pg_dump with –exclude-table — Dumps a database excluding large or unnecessary tables. Essential for creating development snapshots without 50 GB of logs.

pg_dump -d your_db --exclude-table='audit_logs' --exclude-table='raw_events' -Fc > db_dump.dump

Output: A compressed dump file containing everything except those two tables. The -Fc (custom format) allows selective restore.

COPY to/from CSV — The fastest way to import or export bulk data. 10-100x faster than INSERT.

COPY users (email, name, created_at)
TO '/tmp/users_export.csv' DELIMITER ',' CSV HEADER;

COPY users (email, name, created_at)
FROM '/tmp/users_import.csv' DELIMITER ',' CSV HEADER;

Output: First exports all users to CSV. Second imports from CSV. Use FREEZE option for initial data loads to skip WAL logging.

CREATE INDEX CONCURRENTLY — Creates an index without locking the table for writes. Regular CREATE INDEX blocks writes. CONCURRENTLY doesn’t, but takes 2-3x longer.

CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_orders_status_created
ON orders (status, created_at DESC);

Output: Index is built in the background while production reads and writes continue. Monitor progress with pg_stat_progress_create_index.

SET LOCAL for Session Settings — Changes a setting for the current transaction only, not the whole session. Perfect for setting work_mem for one big query without affecting others.

BEGIN;
SET LOCAL work_mem = '256MB';
SET LOCAL statement_timeout = '5min';
SELECT * FROM massive_table ORDER BY complex_column;
COMMIT;

Output: This query gets 256 MB of working memory. Other queries in the session are unaffected. After COMMIT, settings revert to defaults.

Which command should I run first on a slow database?
pg_stat_statements sorted by total_exec_time DESC. It immediately shows you which queries are consuming the most server time. Almost always, 10% of queries cause 90% of the load. Fix those and the database speeds up without touching anything else.
Is CREATE INDEX CONCURRENTLY safe for production?
Yes — it’s the standard method for adding indexes on production tables. It won’t block writes, but it will use I/O and CPU. Run it during low-traffic hours. If it fails (deadlock, conflict), it leaves an invalid index — clean up with DROP INDEX IF EXISTS.
How often should I VACUUM?
PostgreSQL’s autovacuum handles normal workloads automatically. Check pg_stat_user_tables for tables where n_dead_tup keeps growing despite autovacuum. For those, run manual VACUUM ANALYZE or adjust autovacuum_vacuum_scale_factor per table. Heavy-write tables may need a lower threshold like 0.01 (1% dead tuples trigger).

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro