← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Query Optimisation

performance PHP 5.0+ Intermediate
debt(d5/e5/b5/t5)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches' (d5), slow query log, laravel-debugbar, clockwork, and pt-query-digest from detection_hints catch slow queries but require explicit profiling — not silent in prod but not caught by default lint either.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3) but bumped to e5 because per quick_fix multiple changes are needed (EXPLAIN analysis, rewrite subqueries as JOINs, add indexes, narrow SELECT), often touching schema migrations plus query code across a feature.

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

Closest to 'persistent productivity tax' (b5), since applies_to spans web/cli/queue-worker contexts and slow queries become a recurring tax on many work streams; not architecturally load-bearing on their own.

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

Closest to 'notable trap' (t5), the misconception that 'adding an index always fixes a slow query' is a classic documented gotcha — devs eventually learn about function-on-column predicates and covering indexes, but the obvious fix often fails.

About DEBT scoring →

Also Known As

SQL optimisation query tuning slow query optimization

TL;DR

Analysing and rewriting database queries to reduce execution time, I/O, and resource usage.

Explanation

Query optimisation encompasses: using EXPLAIN to understand query plans, adding appropriate indexes, avoiding SELECT * (fetch only needed columns), rewriting correlated subqueries as joins, avoiding functions on indexed columns in WHERE clauses (e.g., WHERE DATE(created_at) = '2025-01-01'), using query caching where appropriate, and batching inserts. In PHP applications, an ORM's query builder can hide inefficient patterns — always profile queries in production using slow query logs or APM tools.

Diagram

flowchart TD
    SLOW[Slow query] --> EXPLAIN2[EXPLAIN ANALYZE]
    EXPLAIN2 --> SEQSCAN{Sequential scan?}
    SEQSCAN -->|yes| INDEX2[Add index on WHERE columns]
    SEQSCAN -->|no| ROWS{Row estimate accurate?}
    ROWS -->|way off| ANALYZE2[ANALYZE table<br/>update statistics]
    ROWS -->|accurate| QUERY_SHAPE[Review query shape]
    subgraph Query_Shape_Fixes
        SELECT_STAR[SELECT star - fetch only needed columns]
        N1_FIX[N+1 - use eager loading]
        FUNC[Function on indexed column<br/>use index on expression instead]
    end
    INDEX2 & ANALYZE2 --> MEASURE[Re-measure execution time]
style SLOW fill:#f85149,color:#fff
style INDEX2 fill:#238636,color:#fff
style MEASURE fill:#1f6feb,color:#fff

Common Misconception

Adding an index always fixes a slow query. Indexes help reads but the query may be slow due to function calls on indexed columns (WHERE YEAR(created_at) = 2024 cannot use an index on created_at), SELECT *, or a missing covering index. EXPLAIN is the first diagnostic step.

Why It Matters

Slow queries are often the single biggest source of application latency — one unindexed query in a hot path can consume more time than all other application code combined.

Common Mistakes

  • Not using EXPLAIN/EXPLAIN ANALYZE before optimising — guessing without the query plan is almost always wrong.
  • SELECT * in queries — fetches unused columns, increasing data transfer and memory.
  • Functions on indexed columns in WHERE: WHERE YEAR(created_at) = 2024 — prevents index use.
  • Not rewriting correlated subqueries as JOINs — correlated subqueries execute once per outer row.

Code Examples

✗ Vulnerable
-- SELECT * fetches all columns — wastes memory and prevents index-only scans
SELECT * FROM orders WHERE status = 'pending';

-- Function on indexed column prevents index use
SELECT * FROM users WHERE YEAR(created_at) = 2024;
✓ Fixed
-- Select only needed columns
SELECT id, user_id, total FROM orders WHERE status = 'pending';

-- Range instead of function — allows index scan
SELECT * FROM users
  WHERE created_at >= '2024-01-01'
    AND created_at  < '2025-01-01';

Added 15 Mar 2026
Edited 22 Mar 2026
Views 37
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings F 0 pings S 1 ping S 2 pings M 0 pings T 0 pings W 0 pings T 0 pings F 2 pings S 0 pings S 0 pings M 2 pings T 0 pings W 1 ping T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 2 pings S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F
No pings yet today
Amazonbot 9 Perplexity 9 SEMrush 4 Unknown AI 3 Ahrefs 2 Google 2
crawler 27 crawler_json 1 pre-tracking 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
Use EXPLAIN ANALYSE, check for full table scans, rewrite subqueries as JOINs, add covering indexes, and avoid SELECT * in production queries
📦 Applies To
PHP 5.0+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
SELECT * queries; correlated subqueries in WHERE; ORDER BY on unindexed column; LIKE '%term%' full-scan
Auto-detectable: ✓ Yes mysql-slow-query-log laravel-debugbar clockwork pt-query-digest
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: Function

✓ schema.org compliant