← Back to Glossary

Query planner

The query planner is the database component that translates a parsed SQL statement into an execution plan — a tree of operators describing how the query will actually be run.

Overview

Once SQL text is parsed into an abstract syntax tree and its table and column references are resolved (a step often called binding), the query planner turns that structure into a plan the execution engine can actually run. This typically happens in two stages: producing a logical plan — an abstract description of the operations needed, like "scan orders, filter by date, join to customers, aggregate by region" — and then a physical plan, which picks concrete algorithms and operators for each logical step, like choosing a hash join over a nested loop join.

Logical vs. Physical Plans

The logical plan describes what needs to happen without committing to how. The physical plan is what the execution engine actually runs: specific join algorithms, specific scan operators, specific aggregation strategies — each chosen (often by a cost-based optimizer) based on the estimated size and characteristics of the data involved.

Planner Responsibilities

Beyond translating logical operations into physical ones, the planner is typically also responsible for applying rule-based rewrites (like predicate and projection pushdown) and, in cost-based systems, deciding join order based on cardinality estimates.

DuckDB's Planner

DuckDB's planner binds a parsed query against the catalog, builds a logical plan, runs it through DuckDB's optimizer pipeline, and produces a physical, vectorized plan made up of operators like SEQ_SCAN, HASH_JOIN, PROJECTION, and HASH_GROUP_BY. Running EXPLAIN on any query shows the physical plan the planner produced, which is the standard way to understand how DuckDB intends to execute a given statement.

Related terms

FAQS

A logical plan describes what operations a query needs (scan, filter, join, aggregate) without specifying algorithms. A physical plan commits to concrete implementations for each step, like a specific join algorithm, chosen by the optimizer.