xiaowei-system/skills/devops/postgres/SKILL.md

6.6 KiB
Executable File

tags name description triggers version
devops
postgres PostgreSQL operations — SQL queries, pg_dump/restore, performance tuning, user management, and common troubleshooting.
postgres
postgresql
pg_dump
psql
pg_restore
数据库
1.0.0

PostgreSQL

Connect

# Local
psql -d mydb
psql -d mydb -U postgres

# Remote
psql -h 192.168.1.10 -p 5432 -d mydb -U postgres

# With URI
psql postgresql://postgres:secret@localhost:5432/mydb

Common Queries

-- List databases
SELECT datname FROM pg_database WHERE datistpl = false;

-- List tables
SELECT tablename FROM pg_tables WHERE schemaname = 'public';

-- List columns
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_name = 'my_table';

-- Describe table
\d my_table
\d+ my_table

-- Row count
SELECT COUNT(*) FROM my_table;

-- Sample rows
SELECT * FROM my_table LIMIT 10;

-- Find rows by condition
SELECT * FROM users WHERE email LIKE '%@gmail.com';

-- Aggregate
SELECT category, COUNT(*) as count, AVG(price) as avg_price
FROM products GROUP BY category HAVING COUNT(*) > 5;

CRUD

-- Insert
INSERT INTO users (name, email, created_at)
VALUES ('Alice', 'alice@example.com', NOW());

-- Multi-row insert
INSERT INTO users (name, email) VALUES
  ('Bob', 'bob@example.com'),
  ('Carol', 'carol@example.com');

-- Update
UPDATE users SET email = 'new@example.com' WHERE id = 42;

-- Delete
DELETE FROM users WHERE id = 42;

-- Upsert (insert or update on conflict)
INSERT INTO users (id, name, email) VALUES (1, 'Alice', 'alice@example.com')
ON CONFLICT (id) DO UPDATE SET email = EXCLUDED.email;

Index

-- Create index
CREATE INDEX idx_users_email ON users(email);

-- Unique index
CREATE UNIQUE INDEX idx_users_email ON users(email);

-- Composite index
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at DESC);

-- Partial index
CREATE INDEX idx_active_users ON users(email) WHERE active = true;

-- Check index usage
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';

Schema

-- Create table
CREATE TABLE products (
    id         SERIAL PRIMARY KEY,
    name       VARCHAR(255) NOT NULL,
    price      DECIMAL(10,2) DEFAULT 0,
    created_at TIMESTAMP DEFAULT NOW()
);

-- Add column
ALTER TABLE products ADD COLUMN category VARCHAR(100);

-- Rename column
ALTER TABLE products RENAME COLUMN price TO unit_price;

-- Drop column
ALTER TABLE products DROP COLUMN IF EXISTS old_col;

-- Add constraint
ALTER TABLE products ADD CONSTRAINT positive_price CHECK (price >= 0);

User / Role Management

-- Create user
CREATE USER alice WITH PASSWORD 'secret_password';

-- Grant privileges
GRANT ALL PRIVILEGES ON DATABASE mydb TO alice;
GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA public TO alice;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO alice;

-- Revoke
REVOKE ALL ON mydb FROM alice;

-- Change password
ALTER USER alice WITH PASSWORD 'new_password';

-- Drop user
DROP USER IF EXISTS alice;

Backup / Restore

# Dump (SQL file)
pg_dump -d mydb -U postgres -f backup.sql
pg_dump -d mydb -U postgres -Fc -f backup.dump    # custom format (compressed)

# Dump all databases
pg_dumpall -U postgres -f all_databases.sql

# Dump specific tables
pg_dump -d mydb -U postgres -t orders -t products > tables.sql

# Restore
psql -d mydb -U postgres -f backup.sql
pg_restore -d mydb -U postgres backup.dump        # custom format

# Restore to new database
createdb newdb
pg_restore -d newdb -U postgres backup.dump

Service Management

# Debian/Ubuntu (systemd)
sudo systemctl start postgresql
sudo systemctl stop postgresql
sudo systemctl restart postgresql
sudo systemctl status postgresql

# Debian/Ubuntu cluster
sudo -u postgres pg_ctlcluster 16 main status
sudo -u postgres pg_ctlcluster 16 main restart

# RHEL/CentOS
sudo systemctl start postgresql-16
sudo systemctl status postgresql-16

Common Maintenance

-- Analyze table (update query planner stats)
ANALYZE users;

-- Vacuum (reclaim space, remove dead rows)
VACUUM users;
VACUUM FULL users;   -- requires exclusive lock, use carefully on live DB

-- Check table size
SELECT pg_size_pretty(pg_total_relation_size('users'));
SELECT pg_size_pretty(pg_relation_size('users'));

-- Check index size
SELECT pg_size_pretty(pg_indexes_size('users'));

-- Find unused indexes
SELECT schemaname, tablename, indexname, idx_scan
FROM pg_stat_user_indexes
WHERE idx_scan = 0;

-- Long-running queries
SELECT pid, now() - pg_stat_activity.query_start AS duration, query
FROM pg_stat_activity
WHERE state != 'idle' AND application_name != 'psql'
ORDER BY duration DESC;

Kill Long Queries

-- Cancel gracefully
SELECT pg_cancel_backend(pid) FROM pg_stat_activity WHERE ...;

-- Hard kill (last resort)
SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE ...;

Performance Tuning

-- Enable measuring query planning/execution time
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT) SELECT ...

Key settings to check in postgresql.conf:

  • shared_buffers — typically 25% of RAM
  • effective_cache_size — typically 75% of RAM
  • work_mem — per-sort memory, increase for large sorts
  • maintenance_work_mem — for VACUUM, CREATE INDEX
  • max_connections — cap at ~100 for most setups

Useful psql Commands

\h          -- SQL help
\h INSERT   -- help on specific command
\du         -- list users/roles
\d          -- list tables
\di         -- list indexes
\ds         -- list sequences
\dv         -- list views
\l          -- list databases
\c mydb     -- connect to database
\dt         -- list tables in current schema
\x          -- toggle expanded display (wide tables)
\i file.sql -- execute SQL file
\copy       -- copy data to/from file
\q          -- quit

Docker

# Run postgres container
docker run -d --name postgres \
  -e POSTGRES_PASSWORD=secret \
  -e POSTGRES_DB=mydb \
  -v postgres_data:/var/lib/postgresql/data \
  -p 5432:5432 \
  postgres:16

# Connect from host
psql -h localhost -p 5432 -U postgres -d mydb

Troubleshooting

Problem Fix
connection refused Check pg_hba.conf allows connection, verify port 5432 is open
password authentication failed Check pg_hba.conf method, reset password or fix connection string
too many clients Increase max_connections or use connection pooler (pgbouncer)
Slow queries EXPLAIN ANALYZE, add indexes, increase work_mem
Disk full VACUUM FULL, delete old WAL archives, pg_dump + pg_restore to new disk
Cannot start after crash Check pg_wal/ integrity, try pg_resetwal, check disk space