Loading...
Loading...
PostgreSQL relational database. Covers SQL queries, indexes, constraints, and performance. Use when working with PostgreSQL. USE WHEN: user mentions "postgres", "postgresql", "pg_", asks about "JSONB queries", "window functions", "recursive CTE", "row level security", "full text search", "partitioning", "pgBouncer", "replication" DO NOT USE FOR: MySQL syntax - use `mysql` instead, MongoDB - use `mongodb` instead, Oracle PL/SQL - use `plsql` instead, SQL Server T-SQL - use `tsql` instead
npx skill4agent add claude-dev-suite/claude-dev-suite postgresqlDeep Knowledge: Usewith technology:mcp__documentation__fetch_docsfor comprehensive documentation.postgresql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
is_active BOOLEAN DEFAULT TRUE
);
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_created ON users(created_at DESC);-- Select with pagination
SELECT * FROM users
WHERE is_active = TRUE
ORDER BY created_at DESC
LIMIT 20 OFFSET 0;
-- Join
SELECT u.*, p.title
FROM users u
LEFT JOIN posts p ON p.user_id = u.id
WHERE u.id = $1;
-- Aggregate
SELECT
DATE_TRUNC('day', created_at) as day,
COUNT(*) as count
FROM users
GROUP BY DATE_TRUNC('day', created_at)
ORDER BY day DESC;
-- Upsert
INSERT INTO users (email, name)
VALUES ($1, $2)
ON CONFLICT (email)
DO UPDATE SET name = EXCLUDED.name;| Type | Use For |
|---|---|
| Auto-increment IDs |
| Unique identifiers |
| Variable strings |
| Long text |
| JSON data (indexed) |
| Date and time |
| True/false |
EXPLAIN ANALYZEJSONBJSONmysqlmongodbredisplsqltsql| Anti-Pattern | Issue | Solution |
|---|---|---|
| Transfers unnecessary data, breaks when schema changes | Specify needed columns explicitly |
Missing | Modifies all rows unintentionally | Always include WHERE clause, use transactions |
| Missing indexes on JOIN/WHERE columns | Full table scans, slow queries | Add indexes on frequently queried columns |
| Using functions on indexed columns | Prevents index usage: | Use functional indexes or change query |
| Cannot use index, full scan | Use |
Missing | Can crash application, memory issues | Always paginate results |
| Storing comma-separated values | Cannot query efficiently, violates normalization | Use array type or junction table |
| Missing foreign keys | Data integrity issues, orphaned records | Define proper FK constraints |
| N+1 query problem | One query per row in loop | Use JOINs or batch queries |
| Long-running transactions | Locks resources, blocks other queries | Keep transactions short, use appropriate isolation |
| Problem | Diagnostic | Fix |
|---|---|---|
| Slow queries | | Add indexes, rewrite query, update statistics |
| High CPU usage | | Optimize top queries, add connection pooling |
| Connection limit reached | | Increase max_connections, use PgBouncer |
| Lock contention | | Reduce transaction time, use lower isolation |
| Disk space full | | VACUUM, archive old data, increase storage |
| Replication lag | Check | Increase resources, tune checkpoint settings |
| Cache hit ratio < 95% | | Increase shared_buffers |
| Dead tuples accumulating | | Run VACUUM, tune autovacuum |
-- Create application user with limited privileges
CREATE USER app_user WITH PASSWORD 'secure_password';
GRANT CONNECT ON DATABASE mydb TO app_user;
GRANT USAGE ON SCHEMA public TO app_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO app_user;
-- Row Level Security (RLS)
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
CREATE POLICY users_tenant_isolation ON users
USING (tenant_id = current_setting('app.tenant_id')::uuid);
-- Force SSL connections
-- In postgresql.conf:
-- ssl = on
-- ssl_cert_file = '/path/to/server.crt'
-- ssl_key_file = '/path/to/server.key'-- Connection with SSL
psql "postgresql://user:pass@host:5432/db?sslmode=require"# pgbouncer.ini
[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 20
min_pool_size = 5
reserve_pool_size = 5# Continuous archiving (WAL)
# postgresql.conf:
archive_mode = on
archive_command = 'cp %p /backup/wal/%f'
wal_level = replica
# Full backup with pg_basebackup
pg_basebackup -D /backup/base -Ft -Xs -P -U replication
# Point-in-time recovery (recovery.signal)
restore_command = 'cp /backup/wal/%f %p'
recovery_target_time = '2024-01-15 10:00:00'-- postgresql.conf recommendations (for 16GB RAM server)
shared_buffers = 4GB # 25% of RAM
effective_cache_size = 12GB # 75% of RAM
maintenance_work_mem = 1GB
work_mem = 64MB
wal_buffers = 64MB
max_connections = 200
checkpoint_completion_target = 0.9
random_page_cost = 1.1 # SSD
-- Query optimization
SET log_min_duration_statement = 1000; -- Log queries > 1s
ANALYZE; -- Update statistics| Metric | Alert Threshold |
|---|---|
| Connection count | > 80% max_connections |
| Cache hit ratio | < 95% |
| Replication lag | > 1MB or > 10s |
| Dead tuples ratio | > 10% |
| Long-running transactions | > 5 minutes |
| Lock wait events | > 10/min |
-- Active connections
SELECT count(*) FROM pg_stat_activity WHERE state = 'active';
-- Cache hit ratio
SELECT
round(100 * sum(blks_hit) / nullif(sum(blks_hit) + sum(blks_read), 0), 2) as cache_hit_ratio
FROM pg_stat_database;
-- Table bloat (dead tuples)
SELECT schemaname, relname, n_dead_tup, n_live_tup,
round(100.0 * n_dead_tup / nullif(n_live_tup + n_dead_tup, 0), 2) as dead_ratio
FROM pg_stat_user_tables
WHERE n_dead_tup > 1000
ORDER BY n_dead_tup DESC;
-- Long-running queries
SELECT pid, now() - pg_stat_activity.query_start AS duration, query
FROM pg_stat_activity
WHERE state = 'active' AND now() - pg_stat_activity.query_start > interval '5 minutes';
-- Replication lag
SELECT client_addr, state,
pg_wal_lsn_diff(pg_current_wal_lsn(), sent_lsn) AS send_lag,
pg_wal_lsn_diff(sent_lsn, replay_lsn) AS replay_lag
FROM pg_stat_replication;# Patroni configuration for HA
scope: postgres-cluster
name: node1
restapi:
listen: 0.0.0.0:8008
etcd:
hosts: etcd1:2379,etcd2:2379,etcd3:2379
postgresql:
listen: 0.0.0.0:5432
data_dir: /data/postgres
parameters:
max_connections: 200
shared_buffers: 4GB