← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

EXPLAIN & Query Plans

Database PHP 5.0+ Intermediate
debt(d5/e3/b3/t5)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). Query plan issues are detected through specialist tools like mysql-slow-query-log, pganalyze, and explain.depesz.com as listed in detection_hints. These aren't default linters but dedicated database performance tools that catch suboptimal execution plans and stale statistics.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix indicates running EXPLAIN ANALYZE to identify the issue, then ANALYZE TABLE to update statistics — a straightforward diagnostic-then-fix pattern. However, acting on the plan may require adding indexes or restructuring queries across a few files, pushing slightly beyond a one-liner but staying within a single component's scope.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). Query plan analysis applies to database interactions in web and cli contexts per applies_to, but the knowledge and discipline to check plans is localised to database-touching code. It doesn't impose system-wide architectural constraints — it's a skill and practice that pays off in specific areas without reshaping the entire codebase.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap' (t5). The misconception explicitly states developers believe query plans are static and always the same for a given query, when in fact they're dynamic based on table statistics and data distribution. This is a documented gotcha that most developers eventually learn through painful production incidents with stale statistics, matching the t5 anchor.

About DEBT scoring →

Also Known As

query execution plan EXPLAIN query SQL explain plan

TL;DR

EXPLAIN (ANALYZE) reveals how the database executes a query — sequential scans, index scans, join strategies — to guide optimisation.

Explanation

EXPLAIN shows the execution plan the query planner chose; EXPLAIN ANALYZE actually executes and shows real timing alongside estimates. Key plan nodes: Seq Scan (full table read — fine for small tables or non-selective queries), Index Scan (uses index, follows heap pointers), Index Only Scan (PostgreSQL — data from index alone, no heap access), Bitmap Heap Scan (batches index lookups then fetches heap rows), Hash Join / Merge Join / Nested Loop (join strategies). Red flags: Seq Scan on a large table with a filter, high rows estimate vs actual rows (stale statistics — run ANALYZE), Nested Loop on large result sets. MySQL: EXPLAIN FORMAT=JSON or EXPLAIN FORMAT=TREE. PostgreSQL: EXPLAIN (ANALYZE, BUFFERS) shows cache hit rates. Use explain.dalibo.com to visualise PostgreSQL plans.

Common Misconception

A query plan is static and always the same for a given query. Query plans are dynamic — they depend on table statistics, row counts, and available indexes. The same query can use different plans on different data distributions, making stale statistics a common cause of unexpected slow queries.

Why It Matters

Reading the query plan reveals how the database actually executes a query — sequential scans, missing indexes, and bad row estimates are visible in the plan and invisible in the query text.

Common Mistakes

  • Not running EXPLAIN before adding an index — the plan shows whether it would be used.
  • Reading estimated rows instead of actual rows — use EXPLAIN ANALYZE for actual execution stats.
  • Optimising based on a dev dataset that doesn't reflect production data distribution.
  • Ignoring 'Seq Scan' on large tables — almost always needs an index.

Code Examples

✗ Vulnerable
-- Slow query, no investigation:
SELECT * FROM events WHERE user_id = 42 AND type = 'login' ORDER BY created_at DESC;
-- Just add EXPLAIN ANALYZE:
-- Seq Scan on events (cost=0.00..45231.00 rows=1000000)
-- -> Missing index on (user_id, type, created_at)
✓ Fixed
-- PostgreSQL EXPLAIN ANALYZE — read this output
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
    SELECT u.name, COUNT(o.id) AS order_count
    FROM users u
    LEFT JOIN orders o ON o.user_id = u.id
    WHERE u.created_at > '2024-01-01'
    GROUP BY u.id;

-- Key nodes to understand:
-- Seq Scan: reads every row — OK for small tables, bad on large ones
-- Index Scan: uses index, then fetches heap row
-- Index Only Scan: reads from index alone (fastest for covered queries)
-- Hash Join: hashes smaller table, probes it for each row of larger table
-- Nested Loop: for each outer row, scans inner — fast for small inner sets

-- 'actual rows=1 loops=1000' → inner loop ran 1000 times — consider Hash Join
-- 'Buffers: hit=5000 read=0' → all from cache — good
-- 'Buffers: hit=100 read=4900' → lots of disk reads — needs index or caching

Added 15 Mar 2026
Edited 22 Mar 2026
Views 100
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 0 pings F 1 ping S 0 pings S 1 ping M 0 pings T 0 pings W 1 ping T 0 pings F 2 pings S 0 pings S 0 pings M 1 ping T 0 pings W 0 pings T 0 pings F 1 ping S
PetalBot 1
No pings yesterday
Amazonbot 12 PetalBot 12 Ahrefs 8 ChatGPT 7 SEMrush 6 Perplexity 4 Unknown AI 4 Scrapy 3 Twitter/X 3 Applebot 2 Majestic 1 Meta AI 1 Brave Search 1 Bing 1
crawler 60 crawler_json 4 pre-tracking 1
🧱 FUNDAMENTALS — new to this? Start with the ground floor.
Database database A database is an organized collection of data stored electronically, designed so programs can efficiently retrieve, add, update, and delete information.

Nearly every application needs to remember information between sessions. Databases provide the reliable, fast, and organized storage that makes persistent data possible at any scale.

💡 Always use prepared statements with placeholders—never concatenate user input directly into database queries.

Ask Codex about Database →
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Medium
⚡ Quick Fix
Run EXPLAIN ANALYZE (PostgreSQL) or EXPLAIN FORMAT=JSON (MySQL) to see actual vs estimated rows — large discrepancy means stale statistics; run ANALYZE TABLE to update them
📦 Applies To
PHP 5.0+ web cli
🔗 Prerequisites
🔍 Detection Hints
Slow query with good index structure but bad execution plan; optimizer choosing full scan over available index due to stale statistics
Auto-detectable: ✓ Yes mysql-slow-query-log pganalyze explain.depesz.com
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: Function


✓ schema.org compliant