PostgreSQL Dev Config Cheatsheet
This cheatsheet covers common PostgreSQL database commands: psql connection, DDL, DML, queries, JOINs, GROUP BY, indexes, backup/restore, and performance analysis.
Connection Management (pg-connect)
``bash
# Connect to local database
psql -d mydb
# Connect to remote database psql -h host.example.com -p 5432 -U user -d mydb
# Execute single SQL and exit psql -d mydb -c "SELECT version();"
# List all databases psql -l
# Execute SQL from file psql -d mydb -f script.sql
# Password-less connection via env var export PGPASSWORD=secret psql -h localhost -U user -d mydb
# Display connection info
\conninfo
`
DDL — Table Structure (pg-ddl)
`sql
-- Create table
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
-- Add column ALTER TABLE users ADD COLUMN age INTEGER DEFAULT 0;
-- Drop column ALTER TABLE users DROP COLUMN age;
-- Change column type ALTER TABLE users ALTER COLUMN name TYPE TEXT;
-- Set default value ALTER TABLE users ALTER COLUMN created_at SET DEFAULT NOW();
-- Add NOT NULL constraint ALTER TABLE users ALTER COLUMN email SET NOT NULL;
-- Drop table DROP TABLE users;
-- Drop if exists DROP TABLE IF EXISTS users;
-- Rename table ALTER TABLE users RENAME TO customers;
-- Describe table structure \d+ users
-- Create index CREATE INDEX idx_users_email ON users(email);
-- Create unique index
CREATE UNIQUE INDEX idx_users_username ON users(username);
`
DML — Data Manipulation (pg-dml)
`sql
-- Insert single row
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');
-- Insert multiple rows INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com'), ('Charlie', 'charlie@example.com');
-- Insert and return generated ID INSERT INTO users (name, email) VALUES ('Dave', 'dave@example.com') RETURNING id;
-- Update data UPDATE users SET name = 'Alice Updated' WHERE id = 1;
-- Update and return UPDATE users SET name = 'Alice New' WHERE id = 1 RETURNING *;
-- Delete data DELETE FROM users WHERE id = 5;
-- Truncate table (preserve structure) TRUNCATE TABLE users;
-- Truncate and reset auto-increment TRUNCATE TABLE users RESTART IDENTITY;
-- Delete and return
DELETE FROM users WHERE id = 5 RETURNING *;
`
Queries & JOINs (pg-query)
`sql
-- Basic queries
SELECT * FROM users;
SELECT id, name, email FROM users;
-- WHERE conditions SELECT * FROM users WHERE age > 18;
-- Sorting SELECT * FROM users ORDER BY created_at DESC;
-- Pagination SELECT * FROM users ORDER BY id LIMIT 10 OFFSET 20;
-- Fuzzy search (LIKE) SELECT * FROM users WHERE name LIKE '%Ali%';
-- IN clause SELECT * FROM users WHERE id IN (1, 2, 3);
-- Range query SELECT * FROM users WHERE created_at BETWEEN '2026-01-01' AND '2026-12-31';
-- INNER JOIN SELECT u.name, o.amount FROM users u JOIN orders o ON u.id = o.user_id;
-- LEFT JOIN SELECT u.name, o.amount FROM users u LEFT JOIN orders o ON u.id = o.user_id;
-- Multi-table JOIN SELECT u.name, o.amount, p.product_name FROM users u JOIN orders o ON u.id = o.user_id JOIN products p ON o.product_id = p.id;
-- Subquery
SELECT name FROM users
WHERE id IN (SELECT user_id FROM orders WHERE amount > 100);
`
Aggregation & Grouping (pg-query)
`sql
-- Count
SELECT COUNT(*) FROM users;
-- Distinct count SELECT COUNT(DISTINCT city) FROM users;
-- Aggregate functions SELECT AVG(age), MAX(age), MIN(age), SUM(salary) FROM employees;
-- GROUP BY SELECT city, COUNT(*) as user_count FROM users GROUP BY city ORDER BY user_count DESC;
-- HAVING filter SELECT city, COUNT(*) as user_count FROM users GROUP BY city HAVING COUNT(*) > 5;
-- GROUP BY with multiple aggregates SELECT department, AVG(salary), MAX(salary), COUNT(*) FROM employees GROUP BY department;
-- DISTINCT
SELECT DISTINCT city FROM users;
`
Index Management (pg-index)
`sql
-- Create regular index
CREATE INDEX idx_users_name ON users(name);
-- Create unique index CREATE UNIQUE INDEX idx_users_email ON users(email);
-- Create composite index CREATE INDEX idx_users_city_age ON users(city, age);
-- Create partial index CREATE INDEX idx_users_active ON users(created_at) WHERE status = 'active';
-- List all indexes on a table SELECT * FROM pg_indexes WHERE tablename = 'users';
-- Show index details \d+ idx_users_name
-- Drop index DROP INDEX idx_users_name;
-- Analyze table (update statistics) ANALYZE users;
-- Rebuild index
REINDEX INDEX idx_users_email;
`
Backup & Restore (pg-backup)
`bash
# Backup single database (custom format)
pg_dump -Fc mydb > mydb.dump
# Backup single database (plain SQL) pg_dump -Fp mydb > mydb.sql
# Compressed backup pg_dump -Fc mydb | gzip > mydb.dump.gz
# Backup specific tables pg_dump -t users -t orders mydb > tables.sql
# Schema-only backup (no data) pg_dump -s mydb > schema.sql
# Data-only backup (no schema) pg_dump -a mydb > data.sql
# Remote backup pg_dump -h remote_host -U user -d mydb > backup.sql
# Restore custom format backup pg_restore -d mydb mydb.dump
# Restore SQL format backup psql -d mydb < mydb.sql
# Parallel restore (multi-core) pg_restore -d mydb -j 4 mydb.dump
# Backup entire cluster
pg_dumpall > full_cluster.sql
`
Performance Tuning (pg-perf)
`sql
-- View query plan (estimated)
EXPLAIN SELECT * FROM users WHERE email = 'alice@example.com';
-- View actual execution plan (with timing) EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'alice@example.com';
-- View slow queries (requires pg_stat_statements) SELECT query, calls, total_time, mean_time FROM pg_stat_statements ORDER BY mean_time DESC LIMIT 10;
-- VACUUM (reclaim storage) VACUUM users;
-- VACUUM FULL (full reclaim, exclusive lock) VACUUM FULL users;
-- Analyze table (update statistics) ANALYZE users;
-- Show autovacuum settings SHOW autovacuum;
-- View active connections SELECT pid, usename, application_name, state, query FROM pg_stat_activity WHERE state = 'active';
-- Terminate a connection SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE pid = 12345;
-- View database size SELECT pg_database_size('mydb');
-- View table size SELECT pg_total_relation_size('users');
-- Human-readable size SELECT pg_size_pretty(pg_database_size('mydb'));
-- Set transaction isolation level
BEGIN;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- ... queries ...
COMMIT;
`
Privilege Management (pg-perf)
``sql -- Create user CREATE USER app_user WITH PASSWORD 'secure_password';
-- Create database with owner CREATE DATABASE mydb OWNER app_user;
-- Grant all privileges GRANT ALL PRIVILEGES ON DATABASE mydb TO app_user;
-- Grant table privileges GRANT SELECT, INSERT, UPDATE ON users TO app_user;
-- Grant schema privileges GRANT USAGE ON SCHEMA public TO app_user;
-- Revoke privileges REVOKE DELETE ON users FROM app_user;
-- List users/roles \du
-- View table privileges \z users
Connection(4)
| Command | Level | ||
|---|---|---|---|
psql -d mydbConnect to local database | Basic | psql -d mydb | |
psql -h host.example.com -p 5432 -U user -d mydbConnect to remote database | Basic | psql -h host.example.com -p 5432 -U user -d mydb | |
psql -d mydb -c "SELECT version();"Execute single SQL and exit | Basic | psql -d mydb -c "SELECT version();" | |
psql -d mydb -f script.sqlExecute SQL from file | Basic | psql -d mydb -f script.sql |
DDL(5)
| Command | Level | ||
|---|---|---|---|
CREATE TABLE users (id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL)Create table with serial PK and NOT NULL | Basic | CREATE TABLE users (id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL); | |
ALTER TABLE users ADD COLUMN age INTEGER DEFAULT 0Add column with default value | Basic | ALTER TABLE users ADD COLUMN age INTEGER DEFAULT 0 | |
ALTER TABLE users DROP COLUMN ageDrop a column | Basic | ALTER TABLE users DROP COLUMN age | |
ALTER TABLE users RENAME TO customersRename table | Basic | ALTER TABLE users RENAME TO customers | |
DROP TABLE IF EXISTS usersDrop table if exists | Basic | DROP TABLE IF EXISTS users |
DML(6)
| Command | Level | ||
|---|---|---|---|
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com')Insert a single row | Basic | INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com'); | |
INSERT INTO users (name, email) VALUES ('Bob', 'bob@test.com'), ('Charlie', 'charlie@test.com')Insert multiple rows | Basic | INSERT INTO users (name, email) VALUES ('Bob', 'bob@test.com'), ('Charlie', 'charlie@test.com'); | |
INSERT INTO users (name, email) VALUES ('Dave', 'dave@test.com') RETURNING idInsert and return generated ID | Intermediate | INSERT INTO users (name, email) VALUES ('Dave', 'dave@test.com') RETURNING id; | |
UPDATE users SET name = 'Alice Updated' WHERE id = 1Update data | Basic | UPDATE users SET name = 'Alice Updated' WHERE id = 1; | |
DELETE FROM users WHERE id = 5 RETURNING *Delete and return deleted data | Intermediate | DELETE FROM users WHERE id = 5 RETURNING *; | |
TRUNCATE TABLE users RESTART IDENTITYTruncate table and reset auto-increment | Intermediate | TRUNCATE TABLE users RESTART IDENTITY; |
Queries(8)
| Command | Level | ||
|---|---|---|---|
SELECT * FROM users WHERE age > 18Conditional query | Basic | SELECT * FROM users WHERE age > 18; | |
SELECT * FROM users ORDER BY created_at DESC LIMIT 10 OFFSET 20Ordered paginated query | Basic | SELECT * FROM users ORDER BY created_at DESC LIMIT 10 OFFSET 20; | |
SELECT * FROM users WHERE name LIKE '%Ali%'Fuzzy search with LIKE | Basic | SELECT * FROM users WHERE name LIKE '%Ali%'; | |
SELECT * FROM users WHERE created_at BETWEEN '2026-01-01' AND '2026-12-31'Date range query | Basic | SELECT * FROM users WHERE created_at BETWEEN '2026-01-01' AND '2026-12-31'; | |
SELECT u.name, o.amount FROM users u JOIN orders o ON u.id = o.user_idINNER JOIN query | Intermediate | SELECT u.name, o.amount FROM users u JOIN orders o ON u.id = o.user_id; | |
SELECT u.name, o.amount FROM users u LEFT JOIN orders o ON u.id = o.user_idLEFT JOIN (preserve all left table rows) | Intermediate | SELECT u.name, o.amount FROM users u LEFT JOIN orders o ON u.id = o.user_id; | |
SELECT city, COUNT(*) as count FROM users GROUP BY city ORDER BY count DESCGROUP BY with count, ordered by count | Intermediate | SELECT city, COUNT(*) as count FROM users GROUP BY city ORDER BY count DESC; | |
SELECT city, COUNT(*) as count FROM users GROUP BY city HAVING COUNT(*) > 5Filter groups with HAVING | Intermediate | SELECT city, COUNT(*) as count FROM users GROUP BY city HAVING COUNT(*) > 5; |
Indexes(4)
| Command | Level | ||
|---|---|---|---|
CREATE INDEX idx_users_email ON users(email)Create regular index | Basic | CREATE INDEX idx_users_email ON users(email); | |
CREATE UNIQUE INDEX idx_users_email ON users(email)Create unique index | Intermediate | CREATE UNIQUE INDEX idx_users_email ON users(email); | |
CREATE INDEX idx_users_city_age ON users(city, age)Create composite index | Intermediate | CREATE INDEX idx_users_city_age ON users(city, age); | |
DROP INDEX idx_users_nameDrop an index | Basic | DROP INDEX idx_users_name; |
Backup(5)
| Command | Level | ||
|---|---|---|---|
pg_dump -Fc mydb > mydb.dumpCustom-format database backup | Basic | pg_dump -Fc mydb > mydb.dump | |
pg_dump -s mydb > schema.sqlSchema-only backup (no data) | Intermediate | pg_dump -s mydb > schema.sql | |
pg_restore -d mydb mydb.dumpRestore database from custom-format backup | Basic | pg_restore -d mydb mydb.dump | |
pg_restore -d mydb -j 4 mydb.dumpParallel restore with multiple jobs | Expert | pg_restore -d mydb -j 4 mydb.dump | |
pg_dumpall > full_cluster.sqlBackup entire database cluster | Intermediate | pg_dumpall > full_cluster.sql |
Performance(7)
| Command | Level | ||
|---|---|---|---|
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'alice@example.com'View actual execution plan with timing | Intermediate | EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'alice@example.com'; | |
VACUUM usersReclaim storage (no lock required) | Intermediate | VACUUM users; | |
VACUUM FULL usersFull storage reclaim (exclusive lock required) | Expert | VACUUM FULL users; | |
ANALYZE usersUpdate table statistics | Intermediate | ANALYZE users; | |
SELECT pg_size_pretty(pg_database_size('mydb'));Human-readable database size | Basic | SELECT pg_size_pretty(pg_database_size('mydb')); | |
SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE pid = 12345;Terminate a specific connection | Expert | SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE pid = 12345; | |
GRANT SELECT, INSERT, UPDATE ON users TO app_user;Grant table-level privileges | Intermediate | GRANT SELECT, INSERT, UPDATE ON users TO app_user; |