Skip to content
Back to skills

Query Plan Reading

ASecurity

Read EXPLAIN ANALYZE output to find the real cause of a slow query and fix the right thing. Use when a query is slow and you need to know why before changing indexes or SQL.

  • 7 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 5, 2026
ai-agentsgosqlnodeperformance

Security analysis

A100/100

Scanned September 5, 2026

npx -y skills add Amey-Thakur/AI-SKILLS --skill query-plan-reading --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Query Plan Reading?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Query Plan Reading
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/amey-thakur-query-plan-reading/badge)](https://www.skillsdirectory.com/skills/amey-thakur-query-plan-reading)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: query-plan-reading
description: Read EXPLAIN ANALYZE output to find the real cause of a slow query and fix the right thing. Use when a query is slow and you need to know why before changing indexes or SQL.
---

# Query plan reading

The query planner tells you exactly how it executes a query and where
the time goes; a slow query is a solved problem once you read its plan.
The mistake is guessing (adding an index, rewriting SQL) without
reading the plan first, and fixing something that was not the
bottleneck.

## Method

1. **Get the real plan with actual numbers.**
   `EXPLAIN ANALYZE` (not just `EXPLAIN`, which estimates):
   it runs the query and reports actual rows and time per
   node. Read it against realistic data volume (a plan on
   ten dev rows tells you nothing about ten million: see
   test-environment-parity); the planner's choices change
   with size.
2. **Find the expensive node.** Plans are trees; read for
   the node consuming the most time and the one processing
   the most rows. The costly operations to spot: sequential
   scans on large tables (missing or unused index: see
   indexing-strategy), nested loops over big row counts,
   large sorts and hashes spilling to disk, and rows
   examined vastly exceeding rows returned (scanning much,
   keeping little).
3. **Compare estimated vs actual rows.** A large gap between
   the planner's estimate and the actual row count means
   stale statistics or a bad estimate, which leads the
   planner to choose the wrong plan (a nested loop where a
   hash join was right). The fix may be updating statistics
   (`ANALYZE`) rather than touching the query: read the gap
   before rewriting.
4. **Confirm the index is used, and why not if not.** A
   sequential scan where you expected an index means: the
   index does not match the query (wrong column order: see
   indexing-strategy), a function wraps the column
   (`WHERE lower(email) = ?` defeats an index on email), an
   implicit type cast, or the planner judged the scan
   cheaper (low selectivity: it may be right). The plan
   shows which; do not add a second index before
   understanding why the first was skipped.
5. **Fix the cause the plan identifies.** Sequential scan on
   a selective filter: add or fix the index. Huge sort: an
   index providing the order, or less data to sort. Nested
   loop over many rows: usually a statistics or join-order
   problem. Rows-examined >> rows-returned: a more selective
   index or a rewritten predicate. Match the fix to the
   node, then re-run EXPLAIN ANALYZE to confirm it worked
   (see sql-optimization).
6. **Verify the fix and watch for regressions.** Re-plan
   after the change (the improvement should show in the
   plan and the time); keep the before/after plans; and
   remember plans change as data grows and statistics
   shift, so a query fast today can regress (see
   pagination-performance, materialized-views for
   structural fixes when tuning hits its limit).

## Boundaries

- Reading the plan finds where time goes; it does not
  decide whether the query should exist (an N+1 pattern is
  a code problem, not a plan problem: see
  n-plus-one-queries, orm-tradeoffs). Sometimes the fix is
  upstream.
- Planner behavior is engine-specific (Postgres, MySQL,
  and others differ in operators and hints); the *method*
  (read the plan, find the expensive node, fix the cause)
  transfers, the exact output does not.
- Some slowness is structural (too much data scanned no
  matter the index): the answer is then partitioning,
  materialized views, or a different data model (see
  data-partitioning, warehouse-modeling), not more index
  tuning.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…