Query Execution Engine
Executor Role
Read aloud is unavailable in this browser.
The Engine That Brings Queries to Life
Every SQL query you write—whether a simple SELECT or a complex multi-table JOIN with aggregations—begins its journey as text and ends as a result set. But between these two endpoints lies a sophisticated machinery that transforms optimized query plans into actual data retrieval operations. This machinery is the Query Execution Engine, often simply called the Executor.
The executor is where theoretical planning meets practical reality. While the query optimizer determines what should happen and in what order, the executor determines how it actually happens at the metal level. It orchestrates data access, coordinates operators, manages memory, and assembles the final results that applications consume.
By the end of this page, you will understand the fundamental responsibilities of the query execution engine, how it interfaces with query plans and physical storage, its position in the overall database architecture, and why its design critically impacts query performance. You'll gain insight into how modern DBMSs implement the executor and the engineering trade-offs involved.
Understanding the Executor's Position in Query Processing
To fully appreciate the executor's role, we must first understand where it fits in the query processing pipeline. Query processing in a relational database management system follows a well-defined sequence of stages, each building upon the output of its predecessor.
The Query Processing Pipeline:
When a SQL query arrives at the database engine, it traverses the following stages:
- Parsing — The SQL text is analyzed for syntactic correctness and converted into a parse tree
- Semantic Analysis — The parse tree is validated for semantic correctness (table/column existence, type compatibility)
- Query Rewriting — The query may be transformed using rules (view expansion, predicate simplification)
- Query Optimization — The optimizer generates and evaluates multiple execution strategies, selecting the optimal plan
- Query Execution — The executor takes the optimized plan and produces actual results
The executor is the terminal stage of this pipeline. It receives an optimized physical query plan (also called an execution plan or access plan) and is responsible for carrying out all the operations specified in that plan.
| Stage | Input | Output | Primary Concern |
|---|---|---|---|
| Parser | SQL text | Parse tree (AST) | Syntactic correctness |
| Semantic Analyzer | Parse tree | Validated query tree | Schema conformance |
| Query Rewriter | Validated tree | Rewritten query tree | Logical transformations |
| Query Optimizer | Logical plan | Physical execution plan | Finding optimal strategy |
| Executor | Physical plan | Result tuples | Efficient execution |
Think of the executor as the bridge between the abstract world of query plans and the concrete world of physical data storage. The optimizer reasons in terms of relational operations and cost estimates; the executor deals with disk I/O, buffer management, memory allocation, and actual tuple manipulation.
Core Responsibilities of the Executor
The query execution engine bears numerous responsibilities that collectively ensure queries execute correctly, efficiently, and reliably. Understanding these responsibilities provides crucial insight into database internals and helps explain observed query behavior.
Primary Responsibilities:
- •Plan Interpretation — Reading and understanding the structure of the physical execution plan, determining which operators to invoke and in what order
- •Operator Instantiation — Creating runtime instances of physical operators (table scans, joins, sorts, aggregations) specified in the plan
- •Data Flow Orchestration — Managing how tuples flow between operators, ensuring correct sequencing and dependencies
- •Resource Management — Allocating and managing memory, temporary storage, and other resources required during execution
- •Buffer Pool Interaction — Coordinating with the buffer manager to fetch pages from disk and manage in-memory caching
- •Error Handling — Detecting and responding to runtime errors, resource exhaustion, and exceptional conditions
- •Result Delivery — Formatting and returning results to the client in the expected format
Supporting Responsibilities:
Beyond these primary duties, the executor also handles several supporting concerns:
- •Statistics Collection — Gathering runtime statistics for query optimization feedback and monitoring
- •Progress Tracking — Maintaining execution state for long-running queries (enabling cancellation, progress reporting)
- •Concurrency Coordination — Interacting with the lock manager and transaction manager to ensure isolation
- •Expression Evaluation — Computing arithmetic expressions, function calls, and predicates on tuples
- •Type Coercion — Handling implicit type conversions as specified in the execution plan
The executor focuses purely on executing the given plan—it does not question whether the plan is optimal. If the optimizer produces a suboptimal plan, the executor will faithfully execute it. This separation of concerns is fundamental to database architecture: the optimizer handles strategy, the executor handles tactics.
The Execution Plan Structure
The executor receives its instructions in the form of a physical execution plan—a tree-structured representation of the query with concrete implementation choices for each operation. Understanding this structure is essential for comprehending how the executor functions.
Physical Plan as an Operator Tree:
A physical execution plan is typically represented as a tree where:
- Each node represents a physical operator (e.g., Sequential Scan, Hash Join, Sort)
- Edges represent data flow between operators
- The root produces the final query result
- Leaves typically access base tables or indexes
Data flows from leaves toward the root: leaf operators produce tuples, intermediate operators transform them, and the root delivers the final result.
1234567891011121314151617181920212223242526272829303132
┌─────────────────────────────────────────────────────┐│ Query: SELECT e.name, d.dept_name ││ FROM employees e JOIN departments d ││ ON e.dept_id = d.id ││ WHERE e.salary > 50000 ││ ORDER BY e.name │└─────────────────────────────────────────────────────┘ Physical Execution Plan: ┌──────────────┐ │ Sort │ ← Root (produces final result) │ (on e.name) │ └──────┬───────┘ │ ┌──────┴───────┐ │ Hash Join │ ← Intermediate operator │(e.dept_id= │ │ d.id) │ └──────┬───────┘ │ ┌────────────┴────────────┐ │ │ ┌──────┴───────┐ ┌──────┴───────┐ │ Filter │ │ Seq Scan │ ← Leaf │(salary>50000)│ │ (departments)│ └──────┬───────┘ └──────────────┘ │ ┌──────┴───────┐ │ Seq Scan │ ← Leaf │ (employees) │ └──────────────┘Operator Nodes Contain:
Each operator node in the physical plan contains detailed information needed for execution:
| Component | Description | Example |
|---|---|---|
| Operator Type | The specific algorithm to use | Hash Join vs. Nested Loop Join |
| Input Schema | Structure of incoming tuples | (id: int, name: varchar, salary: decimal) |
| Output Schema | Structure of produced tuples | (name: varchar, dept_name: varchar) |
| Predicates | Conditions to evaluate | salary > 50000 |
| Expressions | Computations to perform | salary * 1.1, UPPER(name) |
| Access Details | Table/index references | employees table, idx_employees_dept |
| Algorithm Parameters | Implementation-specific settings | Hash table size, sort run count |
Most database systems provide commands to inspect execution plans. PostgreSQL uses EXPLAIN and EXPLAIN ANALYZE, MySQL uses EXPLAIN, and SQL Server uses SET SHOWPLAN_ALL or graphical plan viewers. Understanding how to read these plans is essential for query performance tuning.
The Executor Architecture
Modern database systems implement the executor using a modular, extensible architecture that cleanly separates concerns and allows for flexible operator composition. The most prevalent design pattern is the Volcano or Iterator Model, which we'll explore in depth in the next page. Here, we examine the architectural components that support query execution.
Key Architectural Components:
- •Plan Node Interface — A common interface that all operators implement, enabling uniform treatment regardless of specific operator type
- •Operator Implementations — Concrete implementations of each physical operator type (scans, joins, aggregations, sorts)
- •Expression Evaluator — A component that computes expressions, predicates, and function calls against tuples
- •Tuple Abstraction — A representation of rows that operators manipulate and pass between each other
- •Execution Context — Per-query state including parameters, transaction context, memory limits, and runtime statistics
- •Resource Manager — Controls memory allocation and manages temporary storage for operators requiring external memory
123456789101112131415161718192021222324252627282930313233343536373839
┌─────────────────────────────────────────────────────────────────┐│ Query Execution Engine │├─────────────────────────────────────────────────────────────────┤│ ││ ┌─────────────────────────────────────────────────────────┐ ││ │ Execution Context │ ││ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │ ││ │ │ Query Params│ │ Transaction │ │ Memory Budget │ │ ││ │ └─────────────┘ │ Context │ └─────────────────┘ │ ││ │ └─────────────┘ │ ││ └─────────────────────────────────────────────────────────┘ ││ ││ ┌─────────────────────────────────────────────────────────┐ ││ │ Operator Tree │ ││ │ │ ││ │ ┌────────┐ │ ││ │ │ Sort │ ─────┐ │ ││ │ └───┬────┘ │ │ ││ │ │ │ Expression │ ││ │ ┌───┴────┐ │ Evaluator │ ││ │ │ Hash │ ─────┤ │ ││ │ │ Join │ │ │ ││ │ └───┬────┘ │ │ ││ │ ┌────┴────┐ │ │ ││ │ ┌───┴──┐ ┌───┴──┐ │ │ ││ │ │Scan │ │Scan │ │ │ ││ │ └──────┘ └──────┘ ──┘ │ ││ │ │ ││ └─────────────────────────────────────────────────────────┘ ││ │ ││ ▼ ││ ┌─────────────────────────────────────────────────────────┐ ││ │ Storage Engine Interface │ ││ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │ ││ │ │Buffer Pool │ │ Index Access│ │ Temp Storage │ │ ││ │ └─────────────┘ └─────────────┘ └─────────────────┘ │ ││ └─────────────────────────────────────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────────┘Operator Interface Design:
The elegance of the executor architecture lies in the uniform interface that all operators implement. Regardless of whether an operator is a simple table scan or a complex hash join, it presents the same interface to its parent. This uniformity enables:
- Composability — Any operator can be connected to any other operator that produces compatible output
- Extensibility — New operators can be added without modifying existing infrastructure
- Optimization Transparency — The optimizer can freely substitute equivalent operators without affecting execution machinery
- Testing Simplicity — Each operator can be tested in isolation against the standard interface
The principle of interface uniformity is so powerful that it has remained the foundation of query execution for decades. Whether you're looking at PostgreSQL, MySQL, Oracle, or SQL Server, you'll find variations of this same architectural pattern—operators implementing a common interface, composed into trees, producing tuples on demand.
Interaction with Other Database Components
The executor does not operate in isolation—it constantly interacts with other major database subsystems. Understanding these interactions reveals how different parts of a DBMS collaborate to serve queries.
Key Interaction Points:
| Subsystem | Nature of Interaction | Executor's Role |
|---|---|---|
| Buffer Manager | Page reads/writes | Requests pages, pins/unpins buffers, hints about access patterns |
| Storage Engine | Data access | Invokes scans, seeks, and navigation methods on tables and indexes |
| Lock Manager | Concurrency control | Acquires locks on behalf of the transaction, respects lock waits |
| Transaction Manager | ACID compliance | Operates within transaction boundaries, handles abort cleanup |
| Catalog Manager | Metadata access | Retrieves schema information needed during execution |
| Memory Manager | Resource allocation | Requests and releases memory for operator-specific needs |
| Log Manager | Durability (for DML) | Generates log records for INSERT/UPDATE/DELETE operations |
Buffer Manager Interaction:
The most frequent interaction is with the buffer manager (or buffer pool). The executor continuously requests pages from tables and indexes during query execution. The buffer manager:
- Translates (table_id, page_id) requests into actual disk reads when necessary
- Maintains an in-memory cache of recently accessed pages
- Implements replacement policies (LRU, clock, etc.) to manage cache misses
- Provides pin/unpin semantics so the executor can safely operate on page contents
Efficient buffer management is critical for executor performance. A well-tuned buffer pool can eliminate the majority of physical I/O operations, making the difference between a query completing in milliseconds versus seconds.
- •Request pages through buffer manager
- •Pages may already be in buffer pool (hot cache)
- •If not cached, buffer manager initiates disk I/O
- •Executor operates on in-memory page copy
- •Tuple pointers remain valid while page is pinned
- •Mark pages as dirty after modifications
- •Interaction with WAL (Write-Ahead Logging)
- •Deferred writes (dirty pages flushed later)
- •Coordination with checkpoint mechanism
- •Recovery implications for uncommitted changes
The executor must respect the transaction isolation level when accessing data. It coordinates with the lock manager to acquire appropriate locks (shared for reads, exclusive for writes) and may need to wait if another transaction holds a conflicting lock. Deadlock detection mechanisms ensure the system doesn't permanently stall.
Executor Performance Considerations
The executor's design and implementation profoundly impact query performance. While the optimizer chooses the execution strategy, the executor's efficiency determines how fast that strategy executes. Several factors influence executor performance:
Key Performance Factors:
- •Operator Call Overhead — Every tuple processed incurs function call costs. In a query producing millions of tuples, even microsecond-level overhead compounds significantly
- •Memory Management — Efficient memory allocation and reuse prevents expensive system calls and fragmentation
- •Cache Efficiency — Keeping hot data in CPU caches dramatically speeds up tuple processing; poor memory access patterns cause cache thrashing
- •Predicate Evaluation — Complex expressions evaluated on every tuple become bottlenecks; compiled expressions outperform interpreted ones
- •Data Layout — Row-oriented vs. column-oriented storage affects how efficiently the executor can process data
- •I/O Patterns — Sequential access patterns are dramatically faster than random access due to disk and OS prefetching
The Tuple Processing Overhead Problem:
Traditional row-at-a-time execution (which we'll explore in the Iterator Model page) processes each tuple individually through the operator tree. For a 10-operator plan processing 1 million rows, this means:
- 10 million function calls just for tuple passing
- Millions of virtual function dispatches
- Poor instruction cache utilization due to branching
- Memory access patterns that defeat CPU prefetching
Modern systems address this through techniques like:
- Vectorized Execution — Processing batches of tuples together (covered in later chapters)
- Just-In-Time Compilation — Generating optimized machine code for specific query plans
- Push-Based Execution — Inverting control flow for better cache utilization
| Execution Style | Overhead Per Tuple | Cache Behavior | Best For |
|---|---|---|---|
| Tuple-at-a-time | High (function calls) | Poor (frequent branching) | OLTP, simple queries |
| Vectorized | Low (batched) | Good (predictable access) | OLAP, column stores |
| Compiled | Very Low (no interpretation) | Excellent (tight loops) | Complex analytical queries |
Modern databases expose executor statistics through EXPLAIN ANALYZE (PostgreSQL), execution plans (SQL Server), or equivalent commands. These reveal actual row counts, execution times per operator, buffer hits/misses, and other metrics essential for identifying performance bottlenecks.
Real-World Executor Implementations
Understanding how production database systems implement their executors provides practical insight into the concepts we've discussed. While the core principles remain consistent, each system makes distinct engineering trade-offs.
PostgreSQL Executor:
PostgreSQL's executor is a classic implementation of the Volcano iterator model. Key characteristics include:
- Plan nodes implement Init/Exec/End methods
- Tuples flow one at a time from leaves to root
- Expression evaluation uses a tree-walking interpreter (with optional JIT compilation)
- Extensive use of tuple slots for memory efficiency
- Per-query memory contexts prevent leaks and simplify cleanup
12345678910111213141516171819202122
// PostgreSQL's executor follows the iterator model// Each plan node type implements these methods: ExecInitNode(Plan *node, EState *estate): // Initialize operator state // Recursively initialize child operators // Allocate necessary memory/resources ExecProcNode(PlanState *node): // Return next tuple or NULL if exhausted // Calls appropriate handler based on node type // Example: ExecSeqScan, ExecHashJoin, ExecSort ExecEndNode(PlanState *node): // Clean up operator state // Free allocated resources // Recursively end child operators // Query execution lifecycle:// 1. ExecInitNode on root (cascades down tree)// 2. Repeated ExecProcNode calls until NULL// 3. ExecEndNode on root (cascades down tree)MySQL Executor:
MySQL's execution engine has evolved significantly across versions. The modern implementation features:
- Iterator-based execution (refactored from handler-based in MySQL 8.0+)
- Batch-oriented processing capabilities
- Integration with pluggable storage engines (InnoDB, etc.)
- Handler interface abstracts storage engine differences
Oracle Executor:
Oracle's executor is highly sophisticated, featuring:
- Row sources that produce rows on demand
- Adaptive query execution that can modify plans mid-flight
- Extensive statistics collection during execution
- In-memory columnar processing capabilities
- Real-time plan adjustments based on observed cardinalities
Despite different implementations, all major database systems have converged on similar executor principles: iterator-style interfaces, operator composability, and separation between logical planning and physical execution. This convergence validates the fundamental soundness of the architectural patterns we've discussed.
KEEP LEARNING
There’s more to understand.
You’re reading the introduction. Create a free account to read the complete lesson, save notes and keep track of your progress.