Active Module: Performance & Query Optimizer

Performance Benchmarks

Execute live queries against our seeded database containing 2,500 posts and 50 users to measure execution latency, memory footprint, and view query execution plans.

N+1 Queries vs Eager Loading

Fetching 50 posts and retrieving their user names.

What is happening

Without eager loading, Eloquent fires a new database query for every individual post to retrieve its related user. Eager loading combines this into 2 queries total.

Why it matters

Database network roundtrips are highly expensive. N+1 loops cause latency spikes as database size and page item counts scale.

Expected Performance

Eager Loading (`with('user')`) typically cuts database execution time by 80% to 95% compared to the N+1 loop approach.

Trade-offs

Eager loading increases PHP memory usage slightly since it fetches and keeps the entire relationship map in-memory beforehand.

N+1 Loop (Lazy Loading) Inefficient

Time

Memory

Queries

// Sample of queries executed:

Eager Loaded (with('user')) Optimized

Time

Memory

Queries

// Queries executed:

Database Indexes vs Unindexed Fields

Filtering posts with views > 50,000.

What is happening

Without an index, MySQL executes a **Full Table Scan (ALL)** checking every row. The indexed column uses a B-Tree structure to jump directly to matching nodes.

Why it matters

As tables grow, scanning millions of rows destroys disk I/O, leading to severe query locks and system crashes.

Expected Performance

Indexed reads execute in O(log N) operations (often < 1ms), whereas unindexed scans grow linearly O(N).

Trade-offs

Indexes increase disk usage and slow down writes (INSERT/UPDATE/DELETE) because the index tree must be updated.

Unindexed Lookup (views) Full Scan

Time

Rows Matched

// EXPLAIN Plan:

Type:

Possible Keys:

Key Used:

Rows Scanned:

Indexed Lookup (indexed_views) Index Range

Time

Rows Matched

// EXPLAIN Plan:

Type:

Possible Keys:

Key Used:

Rows Scanned:

Eloquent ORM vs Raw SQL Joining

Fetching 500 records mapped with associated user name.

What is happening

Eloquent hydates 500 individual `Post` objects, constructs relationships, and stores model states. Raw SQL queries bypass model instantiation, fetching simple arrays directly.

Why it matters

Object hydration in PHP is extremely resource-intensive. When processing large data exports, reports, or lists, Eloquent consumes huge amounts of memory and CPU.

Expected Performance

Raw SQL (`DB::select`) typically processes database mappings 3x to 5x faster while using 90% less memory than full Eloquent models.

Trade-offs

Raw SQL lacks security events, custom getters/setters, cast values, state observers, and clean model encapsulation code.

Eloquent ORM Hydration Rich Objects

Time

Hydrated Memory

// Code execution:

Post::with('user')->limit(500)->get();
Raw DB::select Join Fast / Light

Time

Hydrated Memory

// Code execution:

DB::select("SELECT posts.id, posts.title, users.name FROM posts JOIN users ON posts.user_id = users.id LIMIT 500");

OFFSET vs Cursor Pagination

Fetching page 134 (skipping first 2,000 records).

What is happening

`OFFSET 2000` forces the database to read and discard all previous 2,000 records. `Cursor` (where `id > 2000`) uses index positioning to directly load the next 15 records.

Why it matters

Deep offsets cause massive latency spikes on large datasets because the database spends CPU time traversing files it will discard.

Expected Performance

Cursor pagination maintains a constant O(1) query time regardless of how deep the pages go, whereas OFFSET degrades O(N) linearly.

Trade-offs

Cursor pagination does not allow jumping directly to arbitrary pages (e.g. Page 15) and requires sorting columns to have deterministic unique values.

OFFSET Pagination Degrades

Time

// SQL:

Cursor Pagination Constant Time

Time

// SQL: