Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
LaravelPHPJune 23, 20264 min read

Laravel Database Performance: Mastering B-Tree Indexing Strategies

Laravel database performance depends on smart indexing. Learn how to use B-Tree rebalancing and partial indexes to scale Eloquent models under high concurrency.

LaravelEloquentDatabaseMySQLPostgreSQLPerformanceIndexingPHPBackend

Last month, our primary order processing table hit a wall. We were seeing deadlocks during peak traffic hours, and query execution times for our core Order model had climbed from a snappy 15ms to an unpredictable 450ms. The problem wasn't the code; it was the way we were indexing our columns as the table grew past 12 million rows.

If you’re relying on default Eloquent migrations without considering how B-Tree indexing actually behaves under load, you're eventually going to hit this same bottleneck.

Understanding B-Tree Indexing and Laravel Constraints

At the database level, MySQL and PostgreSQL use B-Trees to keep data sorted and searchable. When you add an index to a Laravel migration, you're telling the engine to maintain this balanced tree structure. The issue arises when you have high-cardinality columns that are updated frequently. Every INSERT or UPDATE forces the engine to rebalance the B-Tree nodes.

If your tree is bloated with unnecessary data, the rebalancing cost becomes prohibitive. We initially tried adding a composite index on (status, created_at, user_id). It seemed logical, but because status had low cardinality (only four possible states), the index tree became fragmented. We saw write throughput drop by roughly 30% during high-concurrency bursts.

When you're dealing with these constraints, partial indexes for high-cardinality filtering: A deep dive is your best path forward. Instead of indexing the entire table, you should index only the subset of data that matters.

Implementing Partial Indexes for Eloquent Models

Partial indexes allow you to create an index with a WHERE clause. This drastically reduces the size of the B-Tree, making it faster to traverse and cheaper to rebalance. In Laravel, you can implement this using a raw migration:

PHP
Schema::table('orders', function (Blueprint $table) {
    #6A9955">// Only index active orders, ignoring the millions of completed ones
    $table->index(['user_id', 'created_at'], 'active_orders_index')
          ->where('status', 'pending');
});

This approach keeps the index tree lean. By excluding the "completed" and "cancelled" states from the index, we effectively sliced our index size by about 60%. The B-Tree rebalancing operations became much faster because the engine only needs to worry about the "pending" subset.

When Standard Indexing Fails

Sometimes, even a partial index isn't enough. If your application requires extreme read performance, you might need to look into database performance: Asynchronous Materialized Views for High-Load Reads. Moving heavy read operations away from the primary B-Tree structure allows your writes to remain performant while still serving complex reporting queries.

We also looked at Laravel database sharding: Implementing deterministic horizontal partitioning as a fallback. If your B-Tree is simply too large to fit in memory, no amount of indexing will save you. Sharding splits the data into smaller, manageable chunks, ensuring that each B-Tree remains shallow and fast.

The Trade-offs of Deterministic Indexing

There’s a catch: partial indexes aren't a silver bullet. If your application logic changes and you suddenly need to query "cancelled" orders frequently, your partial index will be ignored by the query planner. You’ll be back to a full table scan, which is often slower than the original unoptimized query.

Before committing to a partial index, verify your query execution plan:

SQL
EXPLAIN ANALYZE SELECT * FROM orders WHERE status = 'pending' AND user_id = 5;

Look for "Index Scan" versus "Seq Scan." If you see a sequential scan, your index isn't being hit. In my experience, it's safer to maintain a slightly redundant index for two weeks, monitor the handler_read_index metrics in your DB, and then drop the old index once you’re certain the new strategy is covering your traffic.

Managing High-Concurrency Writes

If your application suffers from write contention, consider if you're over-indexing. Every index adds overhead to every INSERT. We’ve found that for high-concurrency Laravel apps, limiting the number of indexes per table to five or fewer is a good rule of thumb.

We also learned the hard way that Laravel performance optimization: Building content-aware batching pipelines is essential. If you can batch your database writes, you reduce the frequency of B-Tree rebalancing, which is the single biggest win for write-heavy Eloquent models.

Frequently Asked Questions

Does a partial index work with all Laravel supported databases? It depends on the engine. PostgreSQL supports partial indexes natively. MySQL (prior to version 8.0) does not support WHERE clauses in indexes, so you'd need to use a generated column or a separate table structure to achieve the same effect.

How do I know if my B-Tree is fragmented? Check your database's internal statistics. In MySQL, SHOW TABLE STATUS will give you data on Data_free. If that number is high, your indexes might need an OPTIMIZE TABLE command to rebuild them.

Is it worth using partial indexes for low-cardinality columns? Usually, no. If you have a column with only two values, an index is rarely beneficial unless your query is specifically filtering for the minority value.

I’m still experimenting with index partitioning in MySQL 8.0 to see if it outperforms our current partial index strategy. For now, keeping the trees small and the write operations batched remains the most stable way to keep our Laravel performance consistent.

Back to Blog

Similar Posts

LaravelPHPJune 23, 20264 min read

Laravel Online Schema Change: Mastering Ghost Table Shadowing

Laravel online schema change strategies are essential for high-traffic apps. Learn to use ghost table shadowing to eliminate downtime during migrations.

Read more
LaravelPHPJune 21, 2026
4 min read

CQRS with Materialized Views: Scaling Laravel Read Models

Master CQRS and Materialized Views in Laravel to scale high-concurrency read models. Learn how to decouple your architecture for peak database performance.

Read more
Explore the airy and geometric space of a modern library with intricate staircases and minimalist design.
LaravelPHPJune 20, 20264 min read

Eliminating N+1 queries in Eloquent: A Pragmatic Approach

Eliminating N+1 queries in Eloquent is essential for Laravel performance. Learn how to identify, debug, and solve these database bottlenecks in production.

Read more