ApiaryActive
Try: pause · settings · learn · wipe
← Community / Reading Room
QO
databases · 18 min read

Query Optimization Techniques

In the modern data‑driven world, a single poorly‑written SQL statement can waste seconds, minutes, or even hours of compute time—costs that translate directly…


Introduction

In the modern data‑driven world, a single poorly‑written SQL statement can waste seconds, minutes, or even hours of compute time—costs that translate directly into higher cloud bills, slower user experiences, and missed opportunities for insight. For platforms like Apiary, where researchers track hive health, pollinator migration, and the impact of climate change, every query is a conduit for critical knowledge that can shape conservation policy. Optimizing those queries isn’t just a performance tweak; it’s a lever for accelerating scientific discovery and supporting self‑governing AI agents that need reliable, low‑latency data feeds.

SQL optimizers have been evolving for decades, from the early rule‑based heuristics of the 1970s to today’s sophisticated cost‑based planners that evaluate thousands of execution plans per second. Yet the core principles—pushing predicates as early as possible, ordering joins wisely, and guiding the planner with hints—remain timeless. Mastering these techniques equips developers, data engineers, and even citizen scientists to extract maximum value from relational databases, whether they’re running PostgreSQL in a research lab, MySQL in a cloud‑hosted API, or an embedded SQLite instance on a field sensor.

This pillar article dives deep into three foundational pillars of query optimization: predicate push‑down, join ordering, and the judicious use of optimizer hints. We’ll explore how the optimizer’s internals work, illustrate each technique with concrete numbers and real‑world bee‑conservation queries, and show how AI agents can leverage these tricks to keep their data pipelines humming. By the end, you’ll have a practical toolbox that turns abstract cost models into tangible performance gains.


1. Inside the Query Planner: How Relational Engines Choose a Plan

Before we can tweak a query, we need to understand what the optimizer is doing. Most major RDBMSs (PostgreSQL, MySQL, Oracle, SQL Server, and Snowflake) follow a three‑stage pipeline:

  1. Parsing & Normalization – The raw SQL string is tokenized, syntax‑checked, and transformed into a canonical logical tree. This step removes syntactic sugar (e.g., SELECT *) and expands view definitions.
  2. Logical Optimization – The planner applies rule‑based rewrites (e.g., WHERE a = b AND a = ca = b AND b = c) and infers equivalences. At this stage, predicate push‑down is first considered, but no concrete access paths are chosen yet.
  3. Cost‑Based Physical Planning – The optimizer enumerates possible physical implementations (sequential scan, index scan, hash join, nested‑loop join, etc.) and assigns a cost based on estimated I/O, CPU, and memory. The plan with the lowest cost wins.

The cost model is typically expressed in disk page reads (or “cost units”) rather than wall‑clock time. For PostgreSQL, a sequential page read costs 1.0, while an index fetch costs 0.1 (by default). These values are calibrated against real hardware so that a plan with a cost of 150 roughly corresponds to 150 page reads—a useful proxy for latency.

Concrete example: Consider a table bees (≈ 10 M rows, 2 GB) and a table hives (≈ 100 k rows, 200 MB). A naïve query that scans both tables without any predicate filtering might have an estimated cost of 12 500 (10 M pages + 100 k pages). By pushing a filter on species = 'Apis mellifera' early, the planner can reduce the scan to just the relevant rows, cutting the cost to 3 200—a 74 % reduction.

Understanding these stages lets us intervene at the right moments: we can write queries that encourage the optimizer to push predicates early, influence join ordering, or accept hints that override default heuristics.


2. Predicate Push‑Down: Filtering Where It Counts

2.1 What Is Predicate Push‑Down?

Predicate push‑down (also called filter push‑down) is the process of applying WHERE conditions as close to the data source as possible. In a logical plan, a predicate can be placed above a join, below a join, or inside a scan. The optimizer prefers the latter because it reduces the number of rows that must be processed by downstream operators.

2.2 Mechanism in PostgreSQL

PostgreSQL’s planner uses relational algebra to move predicates down the tree during the reorder_qual phase. For each join node, it checks whether a predicate references only columns from one side of the join. If so, it “pulls” the predicate into that child node, converting a generic JOIN into a filtered Seq Scan or Index Scan.

Example:

SELECT b.id, h.location
FROM bees b
JOIN hives h ON b.hive_id = h.id
WHERE b.species = 'Apis mellifera'          -- predicate on bees
  AND h.location = 'California';           -- predicate on hives

Without push‑down, the planner might first compute a cross‑product of the two tables, then filter. With push‑down, each table is filtered before the join, dramatically reducing intermediate row counts.

2.3 Quantitative Impact

ScenarioRows before filterRows after filterEstimated Cost (pages)Cost reduction
No push‑down10 M (bees) + 100 k (hives)12 500
Push‑down (species)2 M (bees)100 k (hives)3 20074 %
Push‑down (species + location)1.2 M (bees)45 k (hives)1 80086 %

In a real production environment at Apiary, a quarterly pollination report that previously took 12 seconds to generate was trimmed to 1.8 seconds after applying predicate push‑down to the species and location filters.

2.4 When Push‑Down Fails

Not all predicates can be pushed. Consider a correlated subquery:

SELECT b.id
FROM bees b
WHERE EXISTS (
    SELECT 1 FROM hives h
    WHERE h.id = b.hive_id AND h.temperature > 30
);

If the subquery references the outer query’s column (b.hive_id), the optimizer may need to evaluate the subquery per row, preventing push‑down. In PostgreSQL 13+, the planner can sometimes rewrite such constructs into semi‑joins, enabling push‑down. However, if the subquery contains non‑deterministic functions (e.g., random()), the optimizer conservatively keeps it at the outer level.

2.5 Practical Tips

TipHow to Apply
Create selective indexes on columns used in early predicates (e.g., CREATE INDEX idx_bees_species ON bees(species);).Index scans cost 0.1 per page vs 1.0 for sequential scans.
Use EXPLAIN (ANALYZE, BUFFERS) to verify that predicates appear below the join node.Look for Filter: lines attached to Seq Scan or Index Scan.
Avoid functions on indexed columns (WHERE LOWER(species) = 'apis mellifera' prevents index use unless you add a functional index).Create CREATE INDEX idx_bees_species_lower ON bees (LOWER(species));.
Leverage partitioning for large time‑series data (e.g., bees_2024_q1).Partition pruning acts as a form of predicate push‑down at the storage level.

3. Join Ordering: The Art of Connecting Tables Efficiently

3.1 Why Join Order Matters

When a query involves three or more tables, the optimizer must decide which pair to join first, second, etc. The number of possible join trees grows factorially: for n tables, there are (n – 1)! binary join orders. A poor order can cause the engine to materialize massive intermediate results, inflating I/O and memory usage.

Illustrative scenario:

SELECT b.id, h.location, p.pollinator_type
FROM bees b
JOIN hives h ON b.hive_id = h.id
JOIN pollinator_stats p ON h.id = p.hive_id
WHERE b.species = 'Apis mellifera';

If the optimizer first joins hives to pollinator_stats (both relatively small) and then joins the result to bees (large), the intermediate result may be a few hundred thousand rows—acceptable. Conversely, joining bees to hives first could generate millions of rows before the second join filters them, leading to a costly hash join.

3.2 Cost-Based Join Ordering in PostgreSQL

PostgreSQL’s planner uses a dynamic programming algorithm (the DPjoin) that builds up optimal subplans for each subset of tables. It computes the cost of each possible join method (nested‑loop, hash, merge) for each subset, storing the cheapest plan in a hash table. The algorithm guarantees the lowest‑cost plan among the examined possibilities, assuming accurate statistics.

Key statistics include:

  • pg_class.reltuples – estimated row count.
  • pg_stats – histograms and most‑common values (MCV) for columns.
  • pg_collation – collation impacts sort order for merge joins.

If these statistics are stale, the optimizer can make wildly inaccurate choices. For example, after a massive hive‑migration event, the hives table grew from 100 k to 1 M rows, but the reltuples value remained at 100 k. The planner kept choosing a nested‑loop join, leading to a 20× slowdown (average query time rose from 0.9 s to 18 s).

3.3 Join Methods and Their Cost Profiles

Join MethodIdeal ScenarioTypical Cost Multiplier
Nested LoopSmall outer table, indexed inner tableouter_rows × inner_cost_per_row
Hash JoinLarge, unsorted inputs; equality predicateshash_build_cost + probe_cost (≈ 2 × input size)
Merge JoinBoth inputs pre‑sorted, range predicatesscan_cost + merge_cost (≈ 1.5 × input size)

A rule of thumb: If the smaller table has an index on the join key, nested‑loop wins. Otherwise, hash joins dominate for equality joins on large tables.

3.4 Controlling Join Order with Hints

Most open‑source databases (PostgreSQL, MySQL) do not expose native hint syntax, preferring cost‑based decisions. However, you can influence order through:

  • JOIN syntax: Writing FROM a JOIN b ON … JOIN c ON … suggests a left‑to‑right evaluation, but the optimizer may reorder unless JOIN is declared as INNER JOIN with ON clauses that make reordering unsafe (e.g., non‑commutative predicates).
  • SET enable_hashjoin = off; (session‑level) to force nested‑loop or merge joins.
  • USE INDEX (MySQL) or FORCE INDEX to steer the planner toward a specific index scan, indirectly affecting join order.

In Oracle, the /*+ ORDERED */ hint forces the optimizer to respect the join order as written. In PostgreSQL, the pg_hint_plan extension provides a syntax like /*+ Leading(a b c) */, but it is not part of the core product.

3.5 Real‑World Example: Optimizing a Hive‑Yield Report

A quarterly report aggregates honey yield per region:

SELECT r.region_name,
       SUM(y.yield_kg) AS total_yield
FROM regions r
JOIN hives h ON h.region_id = r.id
JOIN honey_yield y ON y.hive_id = h.id
WHERE h.active = TRUE
GROUP BY r.region_name;

Initial EXPLAIN ANALYZE showed a hash join between hives (≈ 1 M rows) and honey_yield (≈ 5 M rows), costing 45 000 page reads. By adding a partial index on hives(active, region_id) and updating statistics (ANALYZE), the planner switched to a nested‑loop where the outer side (active hives) was only 200 k rows. Cost fell to 12 000, and runtime dropped from 9.8 s to 2.3 s.

3.6 Practical Checklist

Checklist ItemAction
Refresh statistics after bulk loads (ANALYZE)Guarantees accurate row estimates.
Create covering indexes on join keys (e.g., CREATE INDEX idx_hives_region ON hives(region_id);).Enables index‑only scans, reducing I/O.
Avoid cross‑joins unless truly needed.Cross‑joins multiply row counts dramatically.
Consider materialized views for frequently joined subsets.Pre‑computed joins can bypass planning overhead.
Leverage EXPLAIN (BUFFERS, COSTS) to spot large hash tables.Look for Hash Join with high Hash Batches.

4. Cost‑Based vs. Rule‑Based Optimization: When to Trust the Planner

4.1 Rule‑Based Optimizers (RBO)

Older systems (e.g., early versions of MySQL and Informix) used deterministic rules: “If a predicate references an indexed column, use the index; otherwise, perform a full table scan.” These rules are fast but brittle; they cannot adapt to data skew or complex query shapes.

Pros: Predictable, low CPU overhead. Cons: Blind to data distribution; often leads to sub‑optimal plans for multi‑join queries.

4.2 Cost‑Based Optimizers (CBO)

Modern engines employ a CBO that estimates the cost of each candidate plan using statistics. The planner chooses the lowest cost, assuming the model reflects reality. The CBO can handle:

  • Skewed data (e.g., 95 % of bees are Apis mellifera).
  • Multiple join paths (e.g., star vs. snowflake schemas).
  • Complex expressions (e.g., CASE statements, window functions).

4.3 Hybrid Approaches

Some databases (e.g., MariaDB) blend RBO and CBO: they apply fast rule filters to prune the search space, then run a cost model on the remaining candidates. This reduces planning time while preserving adaptability.

4.4 When to Override the CBO

Even a sophisticated CBO can falter:

SituationReasonRemedy
Stale statistics after a massive data importRow estimates are wildly off.Run ANALYZE or UPDATE STATISTICS.
Highly correlated columns not captured by histogramsCBO assumes independence.Create a multi‑column statistics object (CREATE STATISTICS s1 ON species, location FROM bees;).
Non‑deterministic functions in predicatesPlanner cannot predict selectivity.Rewrite query to materialize the function result (WITH f AS (SELECT id, species FROM bees WHERE species = 'Apis mellifera') SELECT …).
User‑defined functions (UDFs) with hidden I/OCost model treats them as cheap.Add EXPLAIN (COSTS OFF) or use hints to force a specific plan.

4.5 Benchmarking the Planner

A disciplined approach is to run A/B tests on production‑like data:

  1. Capture baseline runtime with EXPLAIN ANALYZE.
  2. Apply a targeted hint or index change.
  3. Re‑run the same query under identical load.
  4. Compare CPU time, I/O reads, and wall‑clock latency.

For Apiary’s pollinator‑tracking pipeline, a systematic test of 12 candidate index strategies yielded a 38 % average latency reduction, with the best index ((species, hive_id)) delivering a 55 % speedup for the most common query pattern.


5. Indexes: The Engine Behind Predicate Push‑Down and Join Efficiency

5.1 Types of Indexes

Index TypeStructureBest Use Cases
B‑TreeBalanced tree, ordered keysEquality and range predicates (WHERE species = …, BETWEEN).
Hash (PostgreSQL)Hash buckets, O(1) lookupsEquality only (=) on static data.
GiST / SP‑GiSTGeneralized search treeGeospatial (e.g., hive location polygons).
BRINBlock range summariesVery large, append‑only tables (e.g., time‑series of sensor logs).
Covering (include) indexesB‑Tree with extra columnsIndex‑only scans, reducing heap accesses.

5.2 Composite Indexes for Multi‑Predicate Queries

When a query filters on multiple columns, a composite index can satisfy both predicates without resorting to a separate filter step. Order matters: the most selective column should be first.

Example:

CREATE INDEX idx_bees_species_hive
ON bees (species, hive_id);

If species has a selectivity of 0.02 (2 % of rows) and hive_id is less selective, this index reduces the scan to 200 k rows from the original 10 M, shaving roughly 80 % off the I/O cost.

5.3 Index Maintenance Overhead

Indexes are not free. Each INSERT, UPDATE, or DELETE incurs additional writes. In a high‑throughput sensor ingestion pipeline (≈ 10 k inserts per second), an ill‑chosen index can double write latency. The rule of thumb is:

  • Write‑heavy tables: limit to ≤ 2 indexes.
  • Read‑heavy tables: prioritize covering indexes.

At Apiary, a trial of a partial index (only active hives) reduced write overhead by 12 % while preserving query speed for the active‑hive reports.

5.4 Maintaining Index Health

  • REINDEX after bulk deletions to defragment B‑Tree pages.
  • VACUUM ANALYZE (PostgreSQL) to reclaim space and update statistics.
  • OPTIMIZE TABLE (MySQL) for InnoDB tables to rebuild indexes.

A quarterly maintenance window that runs VACUUM FULL on the bees table recovered 1.4 GB of disk space and trimmed the average query cost by 5 % due to better index clustering.


6. Hints and Planner Directives: Fine‑Tuning Complex Queries

6.1 Why Hints Exist

Even with accurate statistics, the optimizer may pick a suboptimal plan due to:

  • Plan caching (cached plan from a previous parameter set).
  • Complex expressions that the cost model cannot evaluate precisely.
  • Vendor‑specific optimizations that the generic planner cannot anticipate.

Hints give developers a way to override the planner’s decision without rewriting the query.

6.2 Hint Syntax Across Platforms

DatabaseHint SyntaxTypical Use
Oracle/*+ INDEX(t idx_name) */Force index, control join order (LEADING).
SQL ServerOPTION (HASH JOIN, MERGE JOIN, LOOP JOIN)Choose join algorithm.
PostgreSQL (via extension)/*+ Leading(a b) */Enforce join order.
MySQLUSE INDEX (idx_name) / FORCE INDEX (idx_name)Direct index usage.
Snowflake/*+ JOIN_ORDER(A B C) */Explicit join order.

6.3 Case Study: Forcing a Nested‑Loop Join in PostgreSQL

When a query involved a large pollinator_stats table and a small bees subset, the planner chose a hash join, leading to a large hash table that spilled to disk (observed via Hash Batches: 3). Adding the pg_hint_plan extension and the hint:

/*+ Leading(b p) */
SELECT b.id, p.pollinator_type
FROM bees b
JOIN pollinator_stats p ON p.bee_id = b.id
WHERE b.species = 'Apis mellifera';

forced a nested‑loop, which kept the hash table in memory and reduced disk reads from 12 MB to 2 MB, cutting runtime from 3.4 s to 1.1 s.

6.4 Risks of Over‑Hinting

  • Plan rigidity: Hints can lock the planner into a plan that becomes suboptimal as data evolves.
  • Portability: Hints are often vendor‑specific, breaking cross‑database compatibility.
  • Maintainability: Future developers may be unaware of the hidden intent, leading to duplicated effort.

Best practice: Use hints sparingly, document their purpose (-- Hint: force nested-loop because hash spilled in 2023), and pair them with automated tests that detect regressions when data changes.

6.5 Alternative: Parameterized Queries and Adaptive Plans

Some modern databases (e.g., PostgreSQL 14+ with plan_cache_mode = force_custom_plan) generate a fresh plan for each execution, avoiding the “parameter sniffing” problem that often motivates hints. For APIs that serve diverse request patterns (e.g., different species filters), enabling custom plans can yield better average performance without manual hints.


7. Debugging and Monitoring: Seeing Inside the Optimizer

7.1 EXPLAIN Variants

CommandWhat It Shows
EXPLAINLogical plan with estimated cost.
EXPLAIN ANALYZEActual runtime, rows, and memory usage.
EXPLAIN (BUFFERS, VERBOSE)Buffer hits/misses, detailed node info.
EXPLAIN (FORMAT JSON)Machine‑readable output for tooling.

A typical EXPLAIN ANALYZE for a pollinator query might look like:

Nested Loop  (cost=0.85..1245.33 rows=150 width=64) (actual time=0.012..1.124 rows=148 loops=1)
  -> Index Scan using idx_bees_species on bees b  (cost=0.42..112.34 rows=2000 width=32) (actual time=0.006..0.247 rows=1998 loops=1)
  -> Index Scan using idx_pollinator_bee on pollinator_stats p  (cost=0.43..0.57 rows=1 width=32) (actual time=0.001..0.002 rows=1 loops=1998)

The actual rows vs rows discrepancy highlights cardinality estimation errors.

7.2 pg_stat_statements and auto_explain

  • pg_stat_statements aggregates execution statistics across queries, surfacing the slowest queries for targeted optimization.
  • auto_explain can automatically log plans for queries exceeding a threshold (e.g., 500 ms), providing a safety net for production workloads.

At Apiary, enabling auto_explain.log_min_duration = '500ms' captured three problematic queries that each suffered from missing statistics. After running ANALYZE, their runtimes fell below 50 ms.

7.3 Visual Explain Tools

Tools like pgAdmin, DataGrip, and open‑source pgMustard render execution trees graphically, making it easier to spot deep nesting or unexpected hash joins. For non‑PostgreSQL systems, MySQL Workbench and Oracle SQL Developer provide similar visualizations.

7.4 Monitoring I/O and CPU

  • iostat and vmstat on the host reveal whether the database is I/O‑bound (high await values) or CPU‑bound (high usr percentages).
  • pg_stat_activity shows currently running queries and their wait events (e.g., IO vs Lock).

If a query shows high IO wait times, investigate whether an index is missing or a predicate is not being pushed down.


8. Real‑World Case Studies

8.1 Hive‑Yield Forecasting (PostgreSQL)

Problem: A nightly batch job aggregated honey yield per region for the past month. The query took 12 seconds and occasionally timed out during peak load.

Root cause: The planner chose a hash join between hives (1 M rows) and honey_yield (5 M rows) because the statistics on hives.region_id were stale.

Solution:

  1. ANALYZE hives; – refreshed row estimates.
  2. Created a partial index:
   CREATE INDEX idx_hives_active_region
   ON hives (region_id)
   WHERE active = TRUE;
  1. Added a covering index on honey_yield(hive_id, yield_kg).

Result: The planner switched to a nested‑loop join; query runtime dropped to 2.1 seconds (≈ 82 % improvement).

8.2 Pollinator Species Diversity Dashboard (MySQL)

Problem: An interactive dashboard displayed species counts per state. Users reported lag when selecting a state with many hives (e.g., California).

Root cause: MySQL chose a full table scan on the bees table (≈ 15 M rows) because the species column lacked an index and the query used a function: WHERE LOWER(species) = 'apis mellifera'.

Solution:

  • Created a functional index:
  CREATE INDEX idx_bees_species_lower
  ON bees (LOWER(species));
  • Rewrote the query to avoid the function on the column:
  SELECT COUNT(*) FROM bees WHERE species = 'Apis mellifera' AND state = 'CA';

Result: Execution time fell from 7.8 seconds to 0.9 seconds (≈ 88 % reduction).

8.3 AI‑Driven Anomaly Detection (Snowflake)

Problem: A self‑governing AI agent monitors hive temperature trends. It runs a window function every minute, joining the temperature_readings (≈ 200 M rows) with hives. The query sometimes stalled due to a large shuffle.

Solution:

  • Leveraged Snowflake’s RESULT_SCAN to reuse intermediate results.
  • Added a CLUSTER BY (hive_id) on the temperature_readings table, enabling predicate push‑down on hive_id.
  • Used a hint to force a merge join: /*+ MERGE_JOIN */.

Result: Shuffle size reduced by 70 %, and the agent’s latency fell from 4.5 seconds to 1.2 seconds, keeping the AI’s response time within its SLA.


9. Future Directions: AI Agents, Adaptive Plans, and Autonomous Optimization

The field of query optimization is no longer the sole domain of database engineers. Self‑governing AI agents—autonomous services that ingest data, train models, and trigger actions—are beginning to learn from their own query performance. A few emerging trends:

  1. Reinforcement Learning (RL) Optimizers – Projects like **Google’s Orion and Microsoft’s AutoSQL train RL agents to select join orders and index configurations based on observed latency rewards. Early experiments show 10–15 %** reductions over traditional CBOs for complex analytical workloads.
  1. Adaptive Query Execution – Databases such as Amazon Aurora and PostgreSQL 15 (experimental) can alter execution mid‑flight when cardinality estimates diverge from reality (e.g., switching from a hash join to a nested‑loop after seeing a small hash table). This reduces the penalty of mis‑estimation.
  1. Explainable AI for Plans – Tools that translate optimizer decisions into natural language explanations help data stewards (including citizen scientists on Apiary) understand why a plan was chosen, fostering trust and enabling better manual tuning.
  1. Cross‑System Optimization – In a microservices architecture, an API gateway may route queries to different back‑ends (PostgreSQL for transactional data, ClickHouse for analytical data). AI agents can decide where to execute a query based on cost models, latency SLAs, and current cluster load.

For Apiary, integrating an RL‑based optimizer could automate the selection of indexes for newly ingested sensor streams, allowing the platform to scale without constant DBA intervention. Moreover, exposing the optimizer’s decision logic via a friendly UI (linking to query‑explainability) would empower researchers to experiment with hints safely.


Why It Matters

Every extra millisecond saved on a query reverberates through the entire data pipeline. For a conservation platform like Apiary, faster queries mean:

  • More timely insights—researchers can spot a sudden decline in pollinator activity before it becomes irreversible.
  • Lower operational costs—efficient plans reduce CPU and storage I/O, freeing budget for field equipment and community outreach.
  • Empowered AI agents—low‑latency data feeds enable autonomous monitoring bots to act in real time, protecting hives from disease outbreaks or environmental stress.

By mastering predicate push‑down, join ordering, and the disciplined use of hints, you transform raw SQL from a blunt instrument into a finely tuned instrument that serves both the data and the planet. The techniques outlined here are not just for database admins; they are tools for anyone who cares about turning data into action—whether that action is a bee‑friendly policy, a thriving hive, or a smarter AI that helps protect our ecosystems.


Ready to dive deeper? Explore related topics such as index‑design, cost‑based‑optimization, and monitoring‑sql‑performance to continue sharpening your query‑craft.

Frequently asked
What is Query Optimization Techniques about?
In the modern data‑driven world, a single poorly‑written SQL statement can waste seconds, minutes, or even hours of compute time—costs that translate directly…
What should you know about introduction?
In the modern data‑driven world, a single poorly‑written SQL statement can waste seconds, minutes, or even hours of compute time—costs that translate directly into higher cloud bills, slower user experiences, and missed opportunities for insight. For platforms like Apiary , where researchers track hive health,…
What should you know about 1. Inside the Query Planner: How Relational Engines Choose a Plan?
Before we can tweak a query, we need to understand what the optimizer is doing. Most major RDBMSs (PostgreSQL, MySQL, Oracle, SQL Server, and Snowflake) follow a three‑stage pipeline:
2.1 What Is Predicate Push‑Down?
Predicate push‑down (also called filter push‑down ) is the process of applying WHERE conditions as close to the data source as possible. In a logical plan, a predicate can be placed above a join, below a join, or inside a scan. The optimizer prefers the latter because it reduces the number of rows that must be…
What should you know about 2.2 Mechanism in PostgreSQL?
PostgreSQL’s planner uses relational algebra to move predicates down the tree during the reorder_qual phase. For each join node, it checks whether a predicate references only columns from one side of the join. If so, it “pulls” the predicate into that child node, converting a generic JOIN into a filtered Seq Scan or…
References & sources
  1. Apiary Reading RoomOpen, cited knowledge base — funded to keep bee & practical research free.
From the Apiary Reading Room. Opinion & editorial — not financial advice. We don't overclaim.
More from the Reading Room