Database Indexing
Indexes are a write tax you pay to make a specific read cheap. Name the query first. Do not spray indexes on every foreign key "just in case".
For rewriting one statement, use sql-query-review. For schema change safety, use database-migrations.
Workflow
- Dialect, table size (rows/bytes if known), write rate, and the exact query or EXPLAIN.
- Restate the access path: equality keys, range keys, ORDER BY, and covering columns.
- Propose the smallest index that serves that path (left-prefix, INCLUDE / covering, partial, expression).
- Check existing indexes for redundancy, unused, or wrong column order.
- Call out write cost, bloat, and CREATE INDEX CONCURRENTLY / ONLINE.
- Verification: what EXPLAIN node should disappear, and a rollback (
DROP INDEX CONCURRENTLY).
Output format
## Indexing plan: <table / query>
**Dialect / size assumption:** …
**Target access path:** …
### Proposed indexes
-- CREATE INDEX …
### Why this shape
leading columns, range, covering, partial predicate
### Do not add
…
### Apply / rollback
CONCURRENTLY, lock notes, DROP
### Verify
EXPLAIN expectation
Rules
- Never invent table stats or existing indexes. If missing, say what you assumed or ask for
\d/SHOW INDEX/ EXPLAIN. - Equality columns before range columns in a B-tree.
- Do not recommend an index that the predicate cannot use (function on the column, leading wildcard, implicit cast).
- One new index per proven query until writes hurt. Composite beats three overlapping singles.
- Unique constraints are indexes; do not duplicate them.
- Warehouse engines: talk clustering/partition prune/clustering keys, not "add a B-tree on user_id", unless the engine has them.
CREATE INDEXon a large hot table without CONCURRENTLY/ONLINE is a finding.
Edge cases
- ORM-only: infer the SQL, then index that SQL — not the object graph.
- Many slow queries: rank by frequency × latency; index the top two, not twenty.
- Already indexed and still slow: look at selectivity, heap fetches, mis-estimates, and whether the query should be rewritten (
sql-query-review) instead of another index. - JSON / arrays: expression or GIN only when the predicate matches the operator class.
---