Database

Mastering PostgreSQL Indexes in Production Laravel

The Code Hub Admin
Sep 18, 2026
7 min read

Learn how B-Tree, GIN, and partial indexes work in PostgreSQL to eliminate query bottlenecks and keep queries running under 5ms.

Introduction

PostgreSQL is an extraordinarily robust relational engine, but unindexed queries will quickly degrade response times as tables scale beyond millions of rows.

In this guide, we explore how to design targeted composite and partial indexes in Laravel migrations.

The Cost of Sequential Scans

When PostgreSQL has no suitable index, it falls back to a sequential table scan, loading every single page from disk into memory.

SQL
EXPLAIN ANALYZE 
SELECT * FROM lessons 
WHERE course_id = 42 AND is_free_preview = true;

If lessons contains 500,000 rows, this query may take 120ms or more.

Creating a Composite Index in Laravel

In your migration, create a compound index matching the query's filter order:

PHP
Schema::table('lessons', function (Blueprint $table) {
    $table->index(['course_id', 'is_free_preview'], 'lessons_course_free_idx');
});

Leveraging Partial Indexes

Partial indexes only index rows that satisfy a specific WHERE clause. This drastically reduces index size and write overhead:

PHP
use Illuminate\Support\Facades\DB;

DB::statement('CREATE INDEX lessons_published_active_idx ON lessons (published_at) WHERE status = \'published\';');

Summary

  • Use EXPLAIN (ANALYZE, BUFFERS) to inspect query cost.
  • Add composite indexes based on actual filter and sorting cardinality.
  • Partial indexes are ideal for sparse boolean states or published content.
Topics in this article

Related Knowledge Articles

Explore hasMany, belongsTo, belongsToMany, and polymorphic relationships in Eloquent with proper foreign key indexing and cascading deletes.
Prevent partial data corruption during multi-table writes using DB::transaction() with automatic commit and rollback guarantees.
Understand how lazy loading triggers catastrophic N+1 database queries and how to prevent them using eager loading and Model::preventLazyLoading().