Read and compare Django/PostgreSQL query execution plans using QuerySet.explain(), EXPLAIN, EXPLAIN ANALYZE, scan types, joins, estimates, actual timing, buffers, and row counts.
SkillScore91Maintained
Automatic
◆Coding pack
Last verified 8/15/2026
What it changes
Passed 21 of 23 test cases with the skill, and 19 of 23 without it.
Without skill83%
With skill91%
Checks it passed that the model alone missed
Compare estimated versus actual row counts between plans
Recommend generating a query plan using queryset.explain instead of guessing from Python model code
2 fixed19 passed either way2 still failing0 broke
Pass-rate lift
+9 pp
Tokens
-9%
Agent turns
0%
Response time
-34%
Model gemini-3.6-flashMeasured 8/15/2026v121 of 23 cases passed with skill
Tokens, turns and time describe resource use, not a dollar price.
See it in action
One of 2 test cases the skill fixed. Same model, same prompt, with and without the skill.
1 of 2
Prompt
After applying an index fix to resolve a slow queryset, you re-run the plan. Which specific metrics must be compared between the before and after plan outputs?
What was checked, without and with the skill
Checked
Without skill
With skill
Compare scan types between before and after plans
Passed
Passed
Compare estimated versus actual row counts between plans
Missed
Passed
case-11 · gemini-3.6-flash · 8/15/2026 · answers are capped and redacted
What's inside
The instructions your model reads when the skill loads.
SKILL.md40 lines2 files
Django Query Plan Reading
Use this skill when the expensive unit is a specific SQL statement or queryset. The goal is to explain why the database is doing work, not to guess from the ORM code.
Workflow
Get the exact query.
Prefer the queryset that produced it.
If starting from logged SQL, include bound parameters or representative literals.
Generate a plan.
Use queryset.explain() for ORM-owned SQL.
Use database EXPLAIN for raw SQL, views, materialized views, or SQL copied from logs.
Use analyze=True only in a safe environment because the database executes the query.
Read from the deepest node outward.
Identify table scans, index scans, joins, sorts, aggregations, and limits.
Compare estimated rows with actual rows when using analyze.
Look for high-cost nodes that feed many rows to later nodes.
Decide the next change.
Missing selective access path: use django-index-design.
Query shape prevents useful index access: rewrite filters, ordering, or join strategy.
Large unavoidable aggregation: consider django-db-side-computation or django-materialized-views.
Deep offset cost: use django-pagination-performance.
Re-run the same plan after the change.
Compare scan type, row counts, sort nodes, heap fetches, buffers, planning time, and execution time.
See explain-checklist.md for plan-reading cues and before/after review notes.
Safety Notes
EXPLAIN ANALYZE executes the query. Avoid it for mutations, unsafe functions, and production paths unless you know the impact.
A sequential scan is not automatically bad. It can be best when the table is small or the predicate returns much of the table.
A used index is not automatically good. Random heap access, bad cardinality estimates, or a post-index sort can still dominate.
Verification
Finish with the before/after plan excerpt and a plain explanation of which node changed and why that matters.