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:
tools
Building resilient distributed systems with circuit breakers, retries with full-jitter exponential backoff, retry budgets (per-request 3-attempt + per-client 10% ratio per Google SRE), deadline propagation, and the cascading-failure math (4 layers × 3 retries = 64x amplification). Grounded in Resilience4j, Microsoft Cloud Patterns, AWS Architecture Blog (Marc Brooker), and Google SRE Book.
testing
Designing HTTP cache headers that work correctly across browsers, CDNs, and shared proxies — `Cache-Control` directives per RFC 9111, `stale-while-revalidate` and `stale-if-error` per RFC 5861, the Vary header for varying responses, and surrogate keys for tag-based purging. Grounded in IETF RFCs and Cloudflare/Fastly docs.
development
Use when designing or fixing a Content Security Policy on a real site, choosing between nonce-based and hash-based CSP, adding strict-dynamic, debugging "Refused to execute inline script" errors, deploying CSP in report-only mode first, configuring report-to / report-uri, or auditing an existing policy for unsafe-inline / unsafe-eval / wildcards. Triggers: "CSP blocks legitimate inline script", strict-dynamic, nonce-{RANDOM}, sha256-{HASH}, object-src none, base-uri none, frame-ancestors, Trusted Types, X-Content-Security-Policy obsolete, report-only vs enforced. NOT for general HTTP security headers (HSTS, COOP/COEP), Trusted Types deep dive, CORS configuration, or building a WAF.
tools
Choosing and operating an HTTP API versioning strategy that doesn't break clients — Stripe's date-based pinned versions, the Deprecation/Sunset header pair (RFC 9745 + RFC 8594), URI vs header vs media-type approaches, and the version-transformer pattern. Grounded in Stripe's published architecture and IETF RFCs.