Cheat sheet · No. XI

psql.

psql is two languages at one prompt: backslash meta-commands the client answers from the system catalogs, and plain SQL that goes to the server. \d and friends are just canned catalog queries.

Printable One A4 page
PLATE — psqlFIG. XI db=#\d userscolumntypenullableidbigintnot nullemailtextnot null"users_pkey" PRIMARY KEY (id) \x on wide rows · EXPLAIN ANALYZE the slow oneone page, pinned to the wall.
The reference
CONNECT
psql -h host -U user -d db
Classic flags (prompts for password)
psql "postgres://user@host:5432/db"
Connection URL
\c otherdb
Switch database in place
\conninfo
Where am I connected?
~/.pgpass
host:port:db:user:pass — no prompts
\q
Quit
DESCRIBE
\l
Databases
\dt
Tables (current schema)
\d orders
Columns, types, indexes
\d+ orders
Plus storage and comments
\di \df
Indexes / functions
\dn \du
Schemas / roles
QUALITY OF LIFE
\x auto
Expanded output when rows are wide
\timing
Print each query's duration
\e
Edit the last query in $EDITOR
\watch 2
Re-run the last query every 2s
\i file.sql
Run a script
\o out.txt
Send results to a file (\o to stop)
\! ls
Run a shell command
COPY (CSV IN/OUT)
\copy orders TO 'orders.csv' CSV HEADER
Table → local CSV
\copy orders FROM 'orders.csv' CSV HEADER
Local CSV → table
\copy (SELECT …) TO 'out.csv' CSV HEADER
Any query → CSV
COPY
Same, but server-side: reads/writes the server's filesystem
WHAT'S RUNNING
-- live queries, oldest first
SELECT pid, state,
       now() - query_start AS age,
       left(query, 60) AS query
FROM pg_stat_activity
WHERE state <> 'idle'
ORDER BY age DESC;

-- who is blocking pid 123?
SELECT pg_blocking_pids(123);

-- kill it (politely)
SELECT pg_terminate_backend(123);
SIZES & PLANS
-- biggest tables (incl. indexes)
SELECT relname, pg_size_pretty(
  pg_total_relation_size(relid))
FROM pg_stat_user_tables
ORDER BY pg_total_relation_size(relid)
  DESC LIMIT 10;
EXPLAIN q
Plan only — estimates
EXPLAIN ANALYZE q
Runs it — real rows and times
EXPLAIN (ANALYZE, BUFFERS) q
Plus cache hits vs disk reads
Field notes
\copy vs COPY

\copy reads and writes files on your machine; COPY runs on the server and needs filesystem access there. For a CSV on your laptop, you want \copy.

EXPLAIN ANALYZE executes

It really runs the statement to measure it. Wrap an UPDATE or DELETE in BEGIN … ROLLBACK before analyzing it.

Turn on \x auto

Wide rows wrap into soup. \x auto switches to one-field-per-line output whenever a row is too wide for the terminal, and stays tabular otherwise.

"idle in transaction" is a smell

A session that opened a transaction and wandered off still holds its locks and blocks vacuum. Find it in pg_stat_activity; end it with pg_terminate_backend(pid).

Tip: hit ⌘P / Ctrl-P to save this single page as a PDF or print it for the wall.

Found this useful?