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

MySQL Subqueries

Database Intermediate
debt(d9/e3/b3/t7)
d9 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'silent in production until users hit it' (d9). The detection_hints field explicitly states automated detection is 'no', with only a code_pattern hint. No static analysis tool is listed. Correlated subqueries and IN vs EXISTS misuse execute silently and only reveal performance problems under production-level data volumes — invisible until users experience slow queries.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix states 'Replace correlated subqueries with a JOIN — use EXISTS instead of IN for large subquery result sets.' This is a targeted rewrite of the affected query or small set of queries — more than a one-liner because query logic must be restructured, but contained within one component or query file.

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

Closest to 'localised tax' (b3). The applies_to covers web and cli contexts broadly, but the debt is query-local — a bad subquery pattern imposes a performance tax only on the queries and code paths that call it. The rest of the codebase is generally unaffected unless the pattern is pervasive.

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

Closest to 'serious trap' (t7). The misconception is explicit: developers believe IN (SELECT ...) and EXISTS (SELECT ...) are always equivalent, but EXISTS short-circuits while IN evaluates everything. This contradicts the intuition that two logically equivalent constructs perform equivalently, and the correlated subquery N+1 behaviour also surprises developers familiar with ORM-level N+1 but not SQL-level equivalents.

About DEBT scoring →

Also Known As

SQL subquery correlated subquery MySQL derived table EXISTS vs IN MySQL

TL;DR

A query nested inside another — useful for filtering and deriving values, but correlated subqueries re-execute per outer row and can be O(n²).

Explanation

Subqueries can appear in SELECT (scalar), FROM (derived table), WHERE, or HAVING. Correlated subqueries reference the outer query and re-execute for each outer row — potentially catastrophically slow on large tables. Non-correlated subqueries execute once. IN (subquery) evaluates the full subquery; EXISTS short-circuits on first match — EXISTS is usually faster for large sets. MySQL 8+ improves subquery decorrelation automatically in some cases.

Common Misconception

IN (SELECT ...) and EXISTS (SELECT ...) are always equivalent. EXISTS short-circuits; IN evaluates everything. On large subqueries EXISTS is significantly faster.

Why It Matters

A correlated subquery in a WHERE or SELECT clause is the SQL equivalent of the N+1 problem — executing thousands of times on large datasets and turning a fast query into a slow one.

Common Mistakes

  • Using a correlated subquery in SELECT to fetch a related value — re-executes for every row.
  • Using IN with a large subquery instead of a JOIN or EXISTS.
  • Nesting subqueries more than two levels deep — readability and optimisability both suffer.

Avoid When

  • Avoid correlated subqueries in SELECT — replace with a JOIN.
  • Avoid deep nesting — flatten with CTEs (WITH clause) in MySQL 8 for readability.

When To Use

  • Use EXISTS for semi-join checks — checking whether any related row exists.
  • Use derived tables in FROM for complex aggregations that need to be joined back.

Code Examples

✗ Vulnerable
-- Correlated: re-runs for every user row → O(n²)
SELECT email,
       (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) AS cnt
FROM users u;
✓ Fixed
-- EXISTS short-circuits on first match
SELECT * FROM users u
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id AND o.status = 'paid');

-- Derived table in FROM (executes once)
SELECT u.email, stats.total
FROM users u
JOIN (SELECT user_id, SUM(total) AS total FROM orders GROUP BY user_id) stats
    ON stats.user_id = u.id;

Added 31 Mar 2026
Views 89
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 1 ping S 1 ping S 0 pings M 1 ping T 1 ping 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 0 pings 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 0 pings M 0 pings T 0 pings W 1 ping T 1 ping F 1 ping S
Ahrefs 1
PetalBot 1
PetalBot 9 Google 7 Ahrefs 6 Scrapy 5 SEMrush 5 Perplexity 4 Unknown AI 4 Claude 3 Bing 2 Applebot 2 ChatGPT 1 Meta AI 1 Majestic 1 Twitter/X 1 Brave Search 1 Baidu 1
crawler 48 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
⚙ Fix effort: Medium
⚡ Quick Fix
Replace correlated subqueries with a JOIN — use EXISTS instead of IN for large subquery result sets
📦 Applies To
web cli
🔗 Prerequisites
🔍 Detection Hints
SELECT (SELECT ... WHERE outer.id = ...) or WHERE col IN (SELECT ...)
Auto-detectable: ✗ No
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: Line Tests: Update


✓ schema.org compliant