home / skills / phrazzld / claude-config / database-patterns

database-patterns skill

/skills/database-patterns

This skill helps you implement database patterns for migrations, queries, transactions, and connection pooling to improve reliability and performance.

npx playbooks add skill phrazzld/claude-config --skill database-patterns

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
2.9 KB
---
name: database-patterns
description: |
  Database operations: migrations, queries, transactions, and performance. Use when:
  - Writing database migrations
  - Optimizing queries or adding indexes
  - Managing transactions and connections
  - Setting up connection pooling
  - Designing audit logging
  Keywords: database, migration, SQL, query optimization, index, transaction,
  connection pool, N+1, ORM, audit log
effort: high
---

# Database Patterns

Forward-only migrations, explicit transactions, measured optimization.

## Migrations

**Forward-only. No rollbacks. Maintain backward compatibility:**
```sql
-- Add nullable column (backward compatible)
ALTER TABLE users ADD COLUMN phone VARCHAR(20);

-- Later: make required after backfill
ALTER TABLE users ALTER COLUMN phone SET NOT NULL;
```

**Break large changes into smaller steps. Use feature flags during transitions.**

## Query Optimization

**Always check execution plans before optimizing:**
```sql
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 123;
```

**Index based on actual query patterns:**
```sql
-- Composite for common query
CREATE INDEX idx_orders_user_date ON orders (user_id, created_at DESC);

-- Partial for filtered queries
CREATE INDEX idx_orders_pending ON orders (status) WHERE status = 'pending';
```

**Monitor unused indexes. Remove if `idx_scan < 100`.**

## N+1 Prevention

**Always eager load in loops:**
```python
# Good
users = User.query.options(joinedload(User.posts)).all()

# Bad (N+1)
users = User.query.all()
for user in users:
    print(user.posts)  # N queries!
```

## Transactions

**Scope to single business operation. Keep short:**
```python
async with db.transaction():
    order = await create_order(data)
    await update_inventory(order.items)
    # Commit on exit

# OUTSIDE transaction: send emails, call external APIs
await send_confirmation(order)
```

**Never hold transactions during external calls.**

## Connection Pooling

```python
# Size based on measured peak concurrency
create_engine(
    url,
    pool_size=15,      # Based on load testing
    max_overflow=5,    # Burst capacity
    pool_timeout=30,   # Fail fast
    pool_recycle=3600, # Prevent stale connections
    pool_pre_ping=True # Validate before use
)
```

**Monitor utilization. Alert at 80%.**

## Data Validation

**Validate at boundaries, not just in database:**
```python
# Validate input before INSERT
validated = CreateUserSchema.parse(input)
if await email_exists(validated.email):
    raise ValidationError("Email taken")

# Validate output after retrieval (detect corruption)
return UserOutputSchema.parse(row)
```

## Anti-Patterns

- Rollback migrations (use forward-only)
- Indexes without query pattern analysis
- N+1 queries in loops
- Long-running transactions with external calls
- Relying only on DB constraints for validation
- Default pool settings without measurement

## References

- [audit-logging.md](references/audit-logging.md) - Immutable audit trails

Overview

This skill codifies proven database patterns for migrations, queries, transactions, and performance tuning. It emphasizes forward-only migrations, explicit transaction boundaries, measured indexing, connection pooling, and strategies to prevent N+1 and other anti-patterns. The goal is safer deploys, predictable performance, and easier operations.

How this skill works

The skill inspects schema change strategy, query patterns, and transaction scope and suggests concrete fixes like splitting migrations, adding composite or partial indexes, and eager loading to avoid N+1. It evaluates connection pool settings against measured concurrency and recommends monitoring thresholds. It also enforces validation at boundaries and flags long-running transactions or external calls inside transactions.

When to use it

  • When authoring schema changes or writing migrations
  • When optimizing slow queries or evaluating indexes
  • When designing or reviewing transaction boundaries
  • When configuring connection pooling and capacity planning
  • When adding audit logging or validating input/output

Best practices

  • Write forward-only, backward-compatible migrations and break large changes into small steps
  • Check EXPLAIN (or EXPLAIN ANALYZE) before adding or changing indexes
  • Scope transactions to a single business operation and avoid external calls inside them
  • Base pool_size and max_overflow on measured peak concurrency and alert at ~80% utilization
  • Eager-load associations to prevent N+1 and use partial/composite indexes for common query filters
  • Validate inputs before INSERT and validate outputs after retrieval to detect corruption

Example use cases

  • Rolling out a nullable column, backfilling values, then marking it NOT NULL in a later migration
  • Identifying an N+1 in a REST endpoint and fixing it with joinedload or selectinload in the ORM
  • Adding a composite index for frequent user_id + created_at queries and removing unused indexes after measurement
  • Tuning connection pool_size and pool_timeout after load testing to avoid timeouts under peak traffic
  • Defining transaction scope for order creation and inventory update, and moving email sending outside the transaction

FAQ

Why forward-only migrations instead of rollbacks?

Forward-only migrations keep production safety and simplify deploys. Rollbacks can be unsafe on shared data and often impossible when destructive changes are involved.

How do I decide which indexes to add or remove?

Base decisions on actual query patterns and EXPLAIN output. Create composite or partial indexes for common filters and monitor index usage; remove indexes with consistently low scans or high write cost.