Volcano Model: Pipelined Query Execution
Volcano makes every query operator a generator yielding one tuple per call. Scans, joins, and sorts stream data upward through open-next-close interfaces without materializing intermediates. The hidden cost is millions of virtual calls that stall modern CPUs.
WHY IT EXISTS: Early database systems materialized entire intermediate results between operators, writing massive temporary tables to disk and exhausting memory. The iterator model was invented to avoid this waste by letting tuples flow directly from one operator to the next as soon as they are produced. It decouples what each operator does from how data moves, giving the optimizer freedom to reorder joins and scans without rewriting execution logic.
THE MENTAL MODEL: Think of a query plan as a set of nested coroutines or generators. Each node in the tree is an iterator with three methods: open to initialize state, next to produce the next tuple or an end of stream marker, and close to clean up. When the root node needs a row, it asks its child for one, and that child may ask its own child, pulling data up like lava rising through a volcano. Because each next call returns a single tuple, the entire pipeline stays alive and incremental.
HOW IT WORKS: A table scan iterator opens a file handle and returns one row per next call. A hash join iterator opens its build side, constructs a hash table in memory, then on each probe side next call probes that table and emits matching pairs. A sort iterator is a blocking operator: its open may drain the child entirely into a buffer, sort it, and then its next calls walk that buffer. Parent operators do not know or care whether their children are scans, joins, or sorts; they only call next. This uniformity makes the model extremely modular.
WHEN TO USE IT: Use the Volcano model when query plans vary widely and you want to ship new operators without touching existing code. It shines in OLAP systems with complex ad hoc queries and in educational database kernels where clarity matters more than raw throughput. It also simplifies memory management because operators hold only the state for the current tuple, plus small working buffers.
WHEN NOT TO USE IT: Do not use it when every CPU cycle counts. The tuple at a time abstraction forces a virtual dispatch or function call per tuple, which modern CPUs struggle to predict and inline. Vectorized execution, which processes thousands of tuples per batch, amortizes this overhead and uses SIMD. Similarly, if your workload is simple point lookups or graph traversals with tight loops, the call overhead and cache pollution of the iterator model will dwarf the actual computation.
ONE CANONICAL EXAMPLE: PostgreSQL uses the Volcano model for all of its executor nodes. A sequential scan node implements ExecSeqScan, which fetches one heap tuple and returns it to a nested loop join node. That join node calls its outer and inner subplans for each tuple pair, passing qualified rows upward to a projection node. The entire query runs as a cascade of these calls, with no intermediate table written for pipelined stages.
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.