The Ultimate Laravel + PostgreSQL Query Optimization Checklist (Part 7)

August 20, 2025 (3mo ago)

Jump to FAQs

You've learned the theory, seen the execution plans, and explored advanced patterns. Now, let's put it all together. This is your step-by-step guide to follow whenever you're writing a new query or debugging a slow one.

Think of this as the Ultimate Optimization Algorithm from the book, adapted for your Laravel workflow.

Step 1: Identify Your Query Type: Short or Long?

Before you write a single line of optimization code, ask yourself this fundamental question :

Your answer determines your entire strategy.

Step 2: The Short Query Checklist (The Quick Wins)

If you're dealing with a short query, your goal is to use an index to avoid a Seq Scan.

Step 3: The Long Query Checklist (The Marathon Strategy)

If you have a long query, your goal is to make the table scans and joins as efficient as possible.

Step 4: The Advanced Scenarios Checklist (The Power Tools)

If you've followed the steps above and still face performance issues, especially with complex, nested data, it's time to bring out the heavy machinery.

Final Thought: Optimization is a Habit, Not a Task

The most important takeaway from this entire series is to "think like a database." Make looking at query logs in Telescope a regular part of your development process. When you write a new feature, take the extra minute to run EXPLAIN on the queries it generates.

By making these small checks a regular habit, you'll stop thinking of optimization as a painful chore and start seeing it for what it is: a crucial part of writing clean, scalable, and professional Laravel applications. Happy coding!

Discuss this post:

Frequently Asked Questions

How do I decide if a query is short or long?

Short queries return a tiny targeted set (often by key); long queries scan or aggregate a large share of rows for reports.

What is the first step before tuning a slow query?

Extract the exact SQL (toSql or Telescope) and run EXPLAIN to see the real plan instead of guessing.

Why might a short lookup use a Seq Scan instead of an index?

Missing or non-selective index, function-wrapped column in WHERE, mismatched data types, or leading wildcard patterns.

How do I fix the N+1 'shopping list' problem?

Move queries out of loops using eager loading (with), batching (whereIn), or a single JSON-building function for deep graphs.

When should I aggregate before joining?

When early grouping drastically shrinks a huge table, reducing join input size and memory.

What is the benefit of WHERE EXISTS over a JOIN + DISTINCT?

EXISTS stops at the first match (semi-join) instead of generating duplicates that must later be de-duplicated.

When is a sequential scan acceptable?

For long queries needing most rows; forcing an index would add random I/O without reducing work.

Why use a CTE in PostgreSQL 12+?

For readability and stepwise logic; most CTEs are now inlined so performance matches equivalent subqueries.

When should I create a database view?

For complex reusable join/compute logic referenced in multiple endpoints or reports.

What triggers considering table partitioning?

Very large time-series or log tables where pruning, retention deletes, or wide-range scans become slow.

What is the NORM pattern?

A PostgreSQL function assembling a full nested JSON payload in one call to eliminate multiple relationship queries.

How do I know if an index is actually used?

EXPLAIN shows Index Scan or Bitmap Index Scan referencing that index; absence means it was skipped.

Bitmap Index Scan vs Index Scan—difference?

Bitmap collects matching TIDs then batches heap page reads; plain Index Scan visits rows immediately—bitmap wins for many scattered matches.

Why avoid function calls on indexed columns in WHERE?

Wrapping (e.g., DATE(created_at)) prevents using a normal B-tree index; rewrite as a range predicate.

What is the core optimization habit?

Always inspect generated SQL and its plan early instead of adding reactive fixes later.