skills/postgresql-optimization/SKILL.md
--- license: Apache-2.0 name: postgresql-optimization version: 1.0.0 category: Backend & Infrastructure tags: - postgresql - optimization - query-performance - indexing - tuning --- # PostgreSQL Optimization ## Overview Expert in PostgreSQL performance tuning, query optimization, and database administration. Specializes in EXPLAIN analysis, indexing strategies, connection pooling, partitioning, and production-grade PostgreSQL operations. ## Decision Points ### Index Type Selection
npx skillsauth add curiositech/windags-skills postgresql-optimizationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Expert in PostgreSQL performance tuning, query optimization, and database administration. Specializes in EXPLAIN analysis, indexing strategies, connection pooling, partitioning, and production-grade PostgreSQL operations.
Query Pattern Analysis:
├── Equality lookups (=, IN)?
│ ├── High cardinality column → B-tree index
│ └── Low cardinality (<100 unique) → Consider partial indexes or skip
├── Range queries (>, <, BETWEEN)?
│ ├── Date/time columns → B-tree index (created_at DESC for recent data)
│ ├── Large table (>1M rows) + sparse data → BRIN index
│ └── Regular ranges → B-tree index
├── Full-text search or JSONB containment?
│ ├── JSONB @>, ?, ?& operators → GIN index with jsonb_path_ops
│ ├── Full-text search (tsvector) → GIN index
│ └── JSONB keys/values extraction → GIN index
├── Array operations (ANY, ALL)?
│ └── GIN index on array column
└── Exact hash lookups only?
├── Large table + no range queries → HASH index
└── Default → B-tree index (more flexible)
| EXPLAIN Output Indicator | Decision Path | Action | |--------------------------|---------------|---------| | "Seq Scan" on large table (>10k rows) | Missing index | Create B-tree index on WHERE clause columns | | "Nested Loop" with high cost | Inefficient join | Add index on join keys, consider hash/merge join | | "Sort" with "external merge" | Insufficient memory | Increase work_mem or add index to avoid sort | | High "Rows Removed by Filter" | Late filtering | Move WHERE conditions earlier, use partial index | | "Bitmap Heap Scan" with low selectivity | Index not selective enough | Create multi-column index or partial index |
Application Analysis:
├── Request pattern: Burst traffic?
│ ├── Yes → pool_mode = transaction, max_client_conn = 5x default_pool_size
│ └── No → pool_mode = session, max_client_conn = 2x default_pool_size
├── Query duration: Long-running queries (>30s)?
│ ├── Yes → pool_mode = session, higher reserve_pool_size
│ └── No → pool_mode = transaction for better throughput
└── Database connections available:
├── max_connections > 200 → default_pool_size = max_connections / 4
└── max_connections ≤ 200 → default_pool_size = 20-25
SELECT pg_size_pretty(pg_relation_size('table_name')) shows growing size but SELECT count(*) stableSELECT count(*) FROM pg_stat_activity WHERE state = 'active' near max_connectionsScenario: Dashboard query taking 45 seconds to load monthly sales data
-- Initial slow query
SELECT
u.name,
COUNT(o.id) as order_count,
SUM(o.total_amount) as revenue
FROM users u
JOIN orders o ON o.user_id = u.id
WHERE o.created_at >= '2024-01-01'
AND o.created_at < '2024-02-01'
GROUP BY u.id, u.name
ORDER BY revenue DESC;
Step 1: Analyze current plan
EXPLAIN (ANALYZE, BUFFERS) [query above];
-- Result: Seq Scan on orders (cost=0.00..450000 rows=2000000)
-- Shows: scanning 2M rows to find 50k matching rows
Expert catches: Date range filter eliminating 95% of rows suggests need for date index Novice misses: Might try to optimize the JOIN first instead of the WHERE filter
Step 2: Create targeted index
-- Index for date filtering and JOIN
CREATE INDEX CONCURRENTLY idx_orders_created_user
ON orders (created_at, user_id)
INCLUDE (total_amount);
Step 3: Re-analyze
EXPLAIN (ANALYZE, BUFFERS) [query];
-- New result: Index Scan using idx_orders_created_user (cost=0.43..15000 rows=50000)
-- Query time: 45s → 1.2s
Expert catches: INCLUDE clause enables index-only scan, eliminating table lookup Novice misses: Would create separate indexes instead of one covering index
Do NOT use this skill for:
database-modeler for ERD design and normalization decisionsredis-caching-expert for cache layer architecturedata-pipeline-engineer for ETL performancesite-reliability-engineer for backup strategiesdatabase-migration-expert for schema migrationsevent-streaming-architect for Kafka/streaming solutionsDelegate when:
data-ai
license: Apache-2.0 NOT for unrelated tasks outside this domain.
development
Use when designing caching strategies (cache-aside, write-through, write-behind), implementing distributed locks, building rate limiters, leaderboards, real-time streams (XADD/consumer groups), pub/sub, or tuning eviction policies. Triggers: thundering-herd on cache miss, dogpile on key expiry, Redlock vs SET-NX-PX choice, sliding-window rate limiter, hot-key on a single cluster slot, big-key blowup, MULTI/EXEC across slots, KEYS in production. NOT for Redis Cluster operations/admin (different domain), embedded KV (SQLite, leveldb), in-process LRU caches, or Memcached.
tools
Drawing the `'use client'` boundary correctly in React Server Components apps (Next.js App Router, RSC frameworks) — leaf-pushing, slot composition, serialization rules, and environment poisoning prevention. Grounded in react.dev and Next.js 16 docs.
development
Use when designing rate limiting for an API, choosing between token bucket / sliding window / leaky bucket / fixed window, implementing it in Redis, deciding edge (Cloudflare/Upstash) vs origin enforcement, sizing per-user vs per-IP vs per-endpoint quotas, returning the right 429 response with Retry-After, or fixing the boundary-burst bug in fixed-window limiters. Triggers: 429 too many requests, INCR + EXPIRE, ZADD + ZREMRANGEBYSCORE + ZCARD, X-RateLimit-Remaining header, Cloudflare WAF rate limiting rules, Upstash @upstash/ratelimit, leaky bucket shaping vs policing, distributed rate limiter consistency. NOT for DDoS mitigation specifically (different scale), CAPTCHA / bot management, full WAF design, or per-user quota billing.