Queries, operator by operator · Build a query engine to learn what a query costs

Appendix DGlossary

Terms the book uses, each with the chapter that introduces it. No chapter uses a term before the chapter that introduces it: tests/test_book.py checks every entry.

Arrow IPC. The stream format Arrow uses to move batches between processes: a schema, then batches laid out as they are in memory. ch05

Batch. A slice of a table, a few thousand rows held column by column as Arrow arrays: what one operator hands the next. ch01

Binding. Resolving every name a query uses to what it names: each column to the table it belongs to, checked against the tables’ schemas. ch11

Branch predictor. The part of a processor that guesses which way a branch will go, from the way it went before, so the processor can start on the guessed path at once. ch06

Broadcast. Sending a copy of a whole, small table to every machine, so that a join need not move the large one. ch15

Build side. The input a hash join reads first and holds, in a hash table on its key, until the join ends. ch08

Cache hit. A read whose cache line is already in the cache. ch02

Cache line. The fixed-size block of memory a processor moves between memory and its caches. Reading one byte brings in the whole line. ch02

Cache miss. A read whose cache line is not in the cache, so the whole line is fetched from memory first. ch02

Cardinality estimate. The number of rows a planner expects an operator to produce, made before the query runs. ch01

Column index. Part of a Parquet file’s page index: the smallest and largest value of each page of a column chunk. ch04

Conjunct. One of the parts of a condition joined by AND: each must hold, so each can be tested on its own, wherever its columns are. ch12

Constant folding. Computing every part of an expression that depends on no column once, when the query is planned, instead of for every row. ch06

Cost model. The rule a planner uses to turn its estimates into one number for a whole plan, so that it can choose the plan whose number is least. ch13

Data page. The unit a Parquet column chunk is stored in: a run of a column’s values, encoded and compressed together. ch04

Dictionary page. The page of a dictionary-encoded column chunk that holds its distinct values, which every data page of the chunk refers to by number. ch04

Dynamic programming. Finding the best plan for every set of a query’s tables from the best plans for its parts, smallest sets first, so each is found once. ch13

Equal-depth histogram. Bounds that split a column’s values into buckets holding the same number of values each, however the values are spread. ch13

Expression tree. An expression as a planner holds it: columns and constants at the leaves, and an operator at each inner node, applied to the values of the nodes below it. ch06

External sort. A sort of more rows than memory holds: sorted runs that fit, spilled, then merged a fan-in at a time until one merge hands the rows up in order. ch10

Fan-in. The number of runs one merge reads at once; each needs a batch of memory, and fewer passes are needed the larger it is. ch10

Filter. The operator that keeps the rows for which a predicate is true. ch01

Filter pushdown. Testing a query’s predicates inside the scan, so it hands up only the rows that pass. ch03

Gather. Reading rows by position, in an order given by a list of positions: row k of the output is row positions[k] of the input. A sort, a join and a lookup each end in one. ch02

Hash join. A join that holds one input, the build side, in a hash table on the join key, and streams the other, the probe side, past it, looking each row’s key up. ch08

Hash table. An array of slots in which a key’s hash picks the slot to look in first: how an engine finds a row’s group, or a row’s match. ch07

Heap. A tree kept in an array, in which each node sorts before its children, so the first element is always the best: the top-k keeps the worst of its rows there, to replace it cheaply. ch09

Heavy hitter. A key that holds far more than its share of the rows: a customer who placed a fifth of the orders. ch16

Hive partitioning. Laying out a table’s files in directories named for a column’s value, such as month=2024-03, so a reader can rule out a file from its path. ch05

Independence assumption. Guessing that knowing one condition holds tells you nothing about another, so their selectivities multiply. ch13

Lane. One of the values a vector register holds side by side, each worked on by the same instruction. ch06

Linear probing. Looking in the next slot, and the next, when a key’s slot in a hash table holds another key. ch07

Logical plan. A query’s meaning as a tree of steps, such as reading a table, joining, filtering and grouping, each saying what it hands up and not how. ch01 names it, and ch11 builds one.

Memory limit. The most memory an engine, or a query, may use; an operator that needs more must spill or fail. ch10

Merge join. A join of two inputs sorted by the join key, which walks both from the front together and needs no table. ch08

Misprediction. A branch that goes the other way from the branch predictor’s guess, so the work started on the guessed path is thrown away. ch06

Morsel. A slice of a query’s input one worker takes at a time; for a Parquet scan, a row group. ch14

Offset index. Part of a Parquet file’s page index: where each page of a column chunk starts, and the first row it holds. ch04

Offsets. The buffer of a string array that says where each row’s bytes start and end in its data buffer. ch02

Open addressing. Keeping a hash table’s entries in its array of slots, rather than in lists hanging off them. ch07

Operator. One step of a plan: a job with one input and one output, such as a scan, a filter or a projection. ch01

Optimiser. The part of a planner that rewrites the logical plan by rules, and chooses between plans that give the same rows. ch12

Partial aggregate. A group’s aggregates over part of its rows, such as a count and a sum, combined later with the other parts’ into the group’s aggregates over all of them. ch07

Perfect hash aggregate. An aggregate whose table has a slot for every possible key, found by subtracting the smallest key: possible when the keys are whole numbers from a small, known range. ch07

Physical plan. The operators an engine will run for a query, and how rows flow between them. DuckDB draws it for EXPLAIN. ch01

Pipeline. The operators a morsel passes through, from the scan up to the first operator that must see all its input before it can hand anything up. ch14

Pipeline breaker. An operator that must see all its input before it hands anything up, such as an aggregate, a sort or a join’s build side. A pushed plan is cut into pipelines at each. ch18

Predicate. A condition that each row either meets or does not, such as status = 'returned'. ch01

Probe side. The input a hash join streams past its table, a batch at a time, looking each row’s key up. ch08

Profile. A plan’s operators after a run, each with counters from that run. ch01

Projection. The operator that computes the columns a query returns from the columns it is given, and drops the rest. ch01

Projection pushdown. Reading only the columns a query uses, inside the scan, so no other column’s bytes are fetched. ch03

Pruning. Skipping a row group, unread, because its statistics show no row in it can satisfy the query’s predicates. ch03

Pull model. Running a plan by having each operator ask the one below it for a batch when it needs one, so the top of the plan drives the run. ch01

Push model. Running a plan by having the source loop over its input and hand each batch to the operator above it, and so on up to a sink. ch18

Pushdown. Handing work to the operator that reads the data, so that data never has to leave it. ch03

Query compilation. Writing code for a query from its plan, then compiling and running that code in place of interpreting the plan. ch19

Recursive descent. Parsing with one function for each kind of phrase in a grammar, each calling the functions for the phrases inside it; precedence is one function per level. ch11

Rewrite rule. A change to a logical plan that gives the same rows for no more work, whatever the data: moving a condition down, reading fewer columns. ch12

Row group. A horizontal slice of a Parquet file: every column’s values for a run of rows, with statistics for each column. ch01

Salt. A small number taken from a row and added to a heavy key, so that the key’s rows spread over several machines instead of one. ch16

Scan. The operator that reads rows from storage: the only operator that reads. ch01

Selectivity. The fraction of its input rows a predicate keeps. ch01

Shuffle. Sending every row to the machine that owns its key, by the key’s hash, so that rows with equal keys meet. ch15

SIMD. Single instruction, multiple data: instructions that apply one operation to every lane of a wide register at once. ch06

Sink. An operator that keeps the batches it is handed instead of handing them on: an aggregate’s table, a join’s build side, a query’s result. ch18

Sorted run. A sequence of rows already in order: part of the input a sort finds in order, or a piece of a large sort written to disk, to be merged with the others. ch09

Speedup. How many times sooner a query finishes with several workers than with one. ch14

Spilling. Writing what does not fit in memory to temporary storage, to read it back later: a query finishes in less memory, and pays in bytes written and read. ch10

Stage. The operators between two shuffles of a distributed plan, run the same way on every machine over that machine’s rows. ch17

Syntax tree. The parts of a query’s text as a tree, as the text wrote them, before any name in it is checked. ch11

Table metadata. A file kept beside a table’s data files that lists each of them with the smallest and largest value of every column, so a reader can rule out a file without opening it. ch05

Task. One machine’s run of a stage. ch17

Tee. A step that hands every batch it is pushed to several consumers, so they share one read of their input. ch18

Token. One word, number, string or operator of a query’s text: what a parser reads, once the spaces and comments are dropped. ch11

Top-k. The first k rows in some order, found without sorting every row: an engine keeps the best k seen so far and compares each new row with the worst of them. ch09

Validity bitmap. One bit per value in an Arrow array, saying whether the value is present or null. ch02

Vectorised execution. Evaluating an operator over a batch of values per call, with a kernel, instead of over one row per call. ch06

Built from commit dc21108.

By Chris Snow, in collaboration with Claude (Anthropic) · Prose and figures: CC BY-NC 4.0 · Code: Apache 2.0