SQL Explain
Analyze a SQL or SQLAlchemy query, explain its execution plan, and identify slow joins, sequential scans, and missing indexes. Triggers on phrases like 'sql explain', 'why is this query slow', 'analyz
Files1
View on GitHubSKILL.md.claude/skills/skill-sql-explain/SKILL.md
GitHubPurpose
Give backend engineers a fast, deterministic read on a query's plan and likely bottlenecks before they ship it. Simpler-grants-gov runs Postgres in FedRAMP-Moderate; queries on opportunity, application, and agency are read-hot and sensitive to plan regressions.
When to Invoke
- A repository method or service query is added or modified under
api/src/db/orapi/src/services/. - A developer asks "why is this query slow" or "explain this query".
- Before merging a PR that introduces a new ORM
selectagainst a large table. - During a performance investigation, paired with logs.
When NOT to Invoke
- For migrations — pair with
skill-migration-safety-check. - For trivial primary-key lookups.
- As a substitute for production
EXPLAIN ANALYZE.
Inputs
- target: a raw SQL string, a path to a file containing a SQLAlchemy
select, or the active editor selection. - mode (optional):
static(default — no DB) orlive(runEXPLAINagainst the local dev DB).
Procedure
- Resolve target. If a SQLAlchemy expression, render it via
str(query.compile(dialect=postgresql.dialect(), compile_kwargs={'literal_binds': True})). - In
staticmode, parse the rendered SQL and run heuristic checks:- Tables referenced (extract
FROM/JOIN). - Filterable columns (extract
WHERE/ON). - For each table, cross-reference
api/src/db/models/for declared indexes; flag any filter column without an index. - Detect
SELECT *(warn). - Detect
ORacross columns of different tables (often defeats indexes). - Detect
LIKE '%...%'leading wildcard (no btree index usage). - Detect missing
LIMITon user-facing queries (risk of unbounded result sets). - Detect N+1 patterns:
for ... in ...: session.execute(select(...))in the surrounding 30 lines.
- Tables referenced (extract
- In
livemode, additionally executeEXPLAIN (FORMAT JSON, BUFFERS, ANALYZE OFF)againstlocal-db. Parse:- Top-level cost
- Any
Seq Scanon tables > 10k rows - Any nested loop with > 1000 outer rows
- Cross-reference
documentation/rules/api-*.mdfor project query patterns. - Emit the Output Format. Do not modify files or write to the DB.
Outputs
SQL Explain — api/src/services/opportunities/search_service.py::search_opportunities
Rendered SQL:
SELECT opportunity.id, opportunity.title, agency.name
FROM opportunity
JOIN agency ON agency.id = opportunity.agency_id
WHERE opportunity.posted_date >= '2026-01-01'
AND opportunity.title ILIKE '%grant%'
ORDER BY opportunity.posted_date DESC
Static findings (3):
[WARN] Leading-wildcard ILIKE on `opportunity.title` defeats btree index
Fix: use Postgres trigram (pg_trgm) GIN index, or full-text search
[WARN] No LIMIT clause on user-facing query
Fix: add `.limit(50)` and pagination cursor
[INFO] `opportunity.posted_date` filter — index present? yes (idx_opportunity_posted_date)
Live plan (mode=live):
Total cost: 14823.42
Hot spot: Seq Scan on opportunity (cost=0..14000, rows=120000)
Cause: leading-wildcard ILIKE forces seq scan despite posted_date index
Recommendations:
1. Add GIN index: CREATE INDEX CONCURRENTLY idx_opportunity_title_trgm ON opportunity USING gin (title gin_trgm_ops);
2. Add LIMIT + cursor pagination.
3. Consider promoting search to OpenSearch (already provisioned).
Block merge: no (advisory)
Safety
- Never executes
INSERT/UPDATE/DELETE/DDL. - Live mode runs
EXPLAINonly — neverEXPLAIN ANALYZE(which executes the query). - Never connects to staging or prod DBs.
- Never logs query parameter values that may contain PII.
- Static mode is the default; live mode requires explicit opt-in.
Examples
Example 1 — Leading wildcard
Author writes ILIKE '%grant%' against opportunity.title. Skill flags the seq-scan risk and recommends pg_trgm.
Example 2 — N+1 detection
A list endpoint loops over results and re-queries agency per row. Skill flags the pattern and recommends selectinload(Opportunity.agency).
Example 3 — Live plan confirmation
In mode=live, skill confirms a Seq Scan and quotes the cost; recommends a concurrent index.
Related
.cursor/skills/skill-migration-safety-check/— for the index-creation migration that follows..cursor/skills/skill-impact-analysis/— find other call sites of the slow query.documentation/rules/performance.mdc— query budget guidance.