Vectorized query execution
Use batches to amortize execution overhead while budgeting live columns, validity masks, selection vectors, and memory traffic.
On this page
The question for today
What you’ll understand
- Calculate how batch dispatch changes an explicit overhead model.
- Distinguish vectorized execution from guaranteed SIMD instructions.
- Budget batch memory and identify when a bandwidth ceiling limits improvement.
A database engine can spend substantial work dispatching operators, interpreting types, and moving fields around rather than performing the requested arithmetic. Vectorized execution groups values into batches so a tight loop does more useful work per invocation. The batch is a software execution unit. Its benefits depend on the expressions, representation, hardware, and how much intermediate data must remain live.
Amortize dispatch over multiple rows
In a tuple-at-a-time interface, a small function may be invoked for each output row and repeatedly traverse generic expression machinery. A batch interface passes arrays or column vectors to an operator, allowing one invocation to process many values. The X100 research demonstrates this design direction, but its historical benchmark results are not a speed guarantee for an unrelated database. Use a local model to distinguish per-invocation overhead from per-row work. Batching can reduce the first term while leaving expensive decoding, hashing, or user functions largely unchanged.
Vectorized software is not synonymous with hardware SIMD. A vector loop may use scalar instructions, compiler auto-vectorization, explicit SIMD, or a mixture. Data types, nullability, branches, variable-length strings, and memory dependencies influence what the compiler can do. Likewise, a tuple-oriented engine can compile parts of a query into efficient loops. Compare executed work and measured bottlenecks rather than declaring that one interface name determines all instruction behavior. Preserve overflow, decimal, collation, and NULL semantics when specializing expressions.
A batch needs more than value payload
For fixed-width columns, multiply rows per batch by bytes per column and the number of simultaneously live columns to estimate value payload. Add validity information, selection indices, offsets, variable-length payloads, and allocator overhead where the representation requires them. A filter may keep a selection vector instead of copying survivors immediately. Later operators must interpret those positions consistently, including NULL masks. A batch with only a few surviving rows can still retain a large input buffer until its last consumer finishes.
Very large batches reduce dispatch frequency but can expand working sets, increase latency before yielding, and retain more temporary data. Very small batches can bring dispatch overhead back. The best size is therefore empirical and can differ across operators or workloads. Keep benchmark output and semantics fixed while varying a batch policy. Measure peak live memory, time to first result, and total throughput together, especially for interactive requests sharing workers with analytical scans. The cost model is useful only while its supposedly constant terms remain plausible.
Less overhead can expose a different bottleneck
After dispatch overhead falls, moving data may dominate. Projection, compression, selective filtering, and reuse can then matter more than removing another function call. For the numeric lab here, operational intensity counts floating-point operations per byte transferred between the last-level cache and main memory. A roofline is an upper bound under those definitions, not a prediction for branch-heavy strings or a conversion between database rows and FLOPs. Measure the relevant traffic and operations before using the model to interpret a real query kernel.
Reset the roofline lab, set both intensity I=2 FLOP/byte and bandwidth B=100 GB/s, predict a 200 GFLOP/s ceiling, then Play or Step. Separately Reset, set both I=16 and B=100, predict the fixed 1,000 GFLOP/s compute ceiling, then Play or Step. Playback traces the synthetic roof without changing the chosen kernel. These controls do not vary batch size or run SQL, and their decimal bandwidth units matter. Explain why increasing intensity beyond the ridge cannot raise this fixed compute roof.
Work it through
Price dispatch separately from row work
A hypothetical serial operator processes 1,000,000 rows. Useful work is five nanoseconds per row and dispatch costs 200 nanoseconds per invocation. Compare one-row invocations with batches of 1,000 rows, holding those costs fixed.
Tuple invocations cost 1,000,000×(5+200) ns = 205,000,000 ns, or 205 ms. The model assigns most of that time to dispatch rather than useful row work.
A batch of 1,000 rows requires 1,000 invocations. Useful work remains 5,000,000 ns and dispatch becomes 200,000 ns, totaling 5.2 ms in the simplified model.
The ratio is 205/5.2≈39.42. It is a consequence of the deliberately fixed cost assumptions, not a benchmark claim; memory stalls, decoding, allocations, and changed per-row cost can reduce or reverse the gain.
Batching amortizes the invocation term. A valid performance claim still requires measurement of the actual expressions, representation, and memory behavior.
The living notebook
Explore the model
Interactive lab · roofline
A numeric batch can reach a bandwidth roof
Reset, set both I=2 FLOP/byte and B=100 GB/s, predict min(1000,200)=200 GFLOP/s, then Play or Step. Separately Reset, set both I=16 and B=100, predict 1000 GFLOP/s, then Play or Step. Both runs use the same last-level-cache/main-memory transfer boundary and fixed synthetic compute ceiling; this is not a batch-size or SQL simulator.
- Attainable ceiling
- 640 GFLOP/s
- Ridge intensity
- 12.5 FLOP/byte
- Ceiling regime
- Memory-bound ceiling
Synthetic roofline ceiling min(1000, B·I), in GFLOP/s, with B in decimal GB/s and I in FLOP/byte. Playback traces the roof without changing the selected kernel. This upper-bound model is not a measured throughput prediction, hardware comparison or price model. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.
Look forAmortizing dispatch can expose memory traffic, and a roofline describes a ceiling rather than measured query throughput.
Pause & reason
Check your understanding
Your turn
Try it yourself
A batch has 1,024 rows and three live fixed-width eight-byte columns. Calculate value payload, then name two categories that can make total live memory larger.
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Multiply batch rows by the sum of column widths.
Compare with the solution
The value payload is 1,024×(8+8+8)=24,576 bytes, or 24 KiB. Validity bitmaps, selection indices, variable-length payloads, offsets, allocator metadata, and other simultaneously live batches can add memory. The estimate does not establish cache residency or the best execution batch size.
Keep the idea
Take it with you
- Batching targets repeated dispatch and interpretation costs.
- Vectorized execution and hardware SIMD are related but distinct concepts.
- Account for masks, positions, lifetimes, and the memory boundary behind a performance ceiling.
Read further
Original sources and deeper explanations to follow at your own pace.
Optional progress, saved in this browser when available. Revisit any lesson at any time.
Lesson not marked complete.