Field

When it does not fit

Every count in the other fields charges one for an array access, which is the right model for data in memory and the wrong one for data anywhere else. Here the unit of cost is the block, the model has two parameters that must be stated before anything is optimal, and the algorithms are the ones a database ships.
block transfersIn order, 0 to n−11,0241.0× a scan · 64.0 elements per transferEvery B-th element (B = 64)65,53664.0× a scan · 1.0 elements per transferUniformly at random61,40760.0× a scan · 1.1 elements per transfera scan of this array is 1,024 transfersB = 64, M = 4,096 (M/B = 64)64× between the cheapest order and the dearest

One access, eight kilobytes

The external-memory model with its two parameters stated — the block size B and the memory size M — and why the unit of cost that every analysis on this site assumed is the wrong one as soon as the data does not fit.

10³10⁴10010³n (elements)block transfersM = 256 · fan-in 7M = 1024 · fan-in 31B = 32, M as labelled4 passes against 3

Sorting what will not fit

External merge sort measured in block transfers, why the cost is a staircase in the memory available rather than a curve, and why the base of the logarithm is M/B.

1010010B (elements per block)block transfers per searchtuned for B = 64Sorted arrayB-tree tuned for B = 64van Emde Boas — told nothingM = 16,384, B as drawnone layout, 7 block sizes, no parameter

The layout that is told nothing

Cache-oblivious layout measured against a B-tree tuned for one block size, across seven block sizes — what a parameterless algorithm can claim, and the constant factor it pays for the claim.

elements of block written per key insertedB-tree, in place49.3Log-structured, T = 23.0 · 16× less than the treeLog-structured, T = 42.0 · 25× less than the treeLog-structured, T = 81.0 · 49× less than the treeLog-structured, T = 161.0 · 49× less than the treeB = 64, M = 4,096 (M/B = 64)25× between the two structures at T = 4

The writes nobody counted

Write amplification measured — an in-place B-tree against a log-structured merge tree — and why a read count and a write count are two resources rather than one.

1100ε — the exponent the fanout is B toelements written per key33445679ε = 1 — the B-tree ·fanout 256 · 3transfers a queryε = 0.5 · fanout 16 · 5a querythe number above eachpoint is what a querycostsB = 256, M = 16,384 (M/B = 64)131,072 random keys

One dial between two structures

The buffered tree, measured — how one exponent moves insertion cost from a whole block per key to a fraction of one, what it charges for that on every query afterwards, and where the trade stops paying.

1010010³10⁴B — elements to the blockblock transfersthey cross near B = 4one element at a timesorted by destination, 2passesM = 4,096, B as drawnthe lower bound is the smaller of the two, and it is proved rather than measured

Permuting is the harder problem here

Why moving elements one at a time costs one transfer each, why sorting by destination costs far less, where the two cross, and what a lower bound proved about both.

11010010³10⁴1010010³rows matching the queryblock transfersn/B rows — where the arithmetic says they meetindex, rows scatteredindex, file in key orderread the whole fileB = 64, M = 4,096 (M/B = 64)plus 3 transfers to descend the index

The index that is not worth reading

Three query plans priced in transfers, why the crossover the textbook arithmetic predicts is not the measured one, and what a clustered index changes about all of it.

1×10×10³10⁴the key side, as a multiple of memoryblock transfersblock nested looppartitioned hash joinsort–merge joinB = 64, M = 512 (M/B = 8)the other relation: 16,384 rows

Two ways to join, and the ratio that decides

Block nested loop, partitioned hash and sort–merge joins measured in transfers, why all three return identical answers, and why the choice between them is a ratio rather than a size.

11010010³10⁴12510rows the query actually matchescost ÷ the better plan's costrho plus the descent, 4.01estimate ÷64estimate ÷8estimate ×8estimate ×64n = 65,536, B = 64, M = 4,096 (M/B = 64), scattered read ×4dotted: the estimate switches at 512 rows

The estimate a plan rests on

One planner decision priced at the truth while its row estimate is held wrong by a fixed factor. Overestimates on narrow queries grow with the file, underestimates are capped by the read-cost ratio, and that ratio decides which mistake is the dangerous one.

10⁵10⁶10⁷10³10⁴inversions in the permutationblock transfers to carry it outsort by destination, 1,536w 8w 32w 128w 512w 2048w 819216 swaps64 swaps256 swaps1024 swapsshuffled inside windowsa few pairs swapped farn = 16,384, B = 64, M = 512 (M/B = 8)inversions do not order the cost

The permutation that moves almost nothing

Carrying out a permutation one element at a time, measured against the inversions it contains. The cost follows how far elements move relative to what fits in memory, not how many pairs are out of order, and two permutations can be ordered one way by inversions and the other way by transfers.

1×2×5×10×20×50×00.40.811.2skew of the join columnratio, logarithmicestimate off byregret, decided partregret, whole planR 4,000, S 40,000, T 2,000 rows, B = 64, M = 4,096 (M/B = 64)every order writes the same output

The join order is a guess

A three-way join ordered on an estimate that assumes a uniform join column, swept over skew. The regret over the whole plan stays under 1.5 while the regret on the part the order controls reaches 44 and then 244, because every order writes the same output and that shared cost hides the mistake.

0.020.050.10.20.5121235810filter bits a keywasted reads per absent lookupno filters: all 3 levelssame rate every levelrates sized to levelsn = 65,536, size ratio 4, first run 1,024 keysthe same memory at every point

The filter each run carries

Bloom filters on the runs of a log-structured store, with the same memory divided evenly or sized to each level. Sizing makes an absent lookup's wasted reads nearly independent of how many levels there are, while an even split pays for every level it adds.

1×2×5×10×20×50×100×200×00.250.50.7511.251.51.752skew of the join columnregret of the decided part, logarithmicuniform estimate4 counters a side16 counters a side64 counters a side256 counters a sideR 4,000, S 40,000, T 2,000 rows · 64-record blocks, 4,096 in memoryMisra–Gries on each side of the join column

The skew a few counters cannot repair

The uniform join-size estimate behind a three-way join order, repaired with Misra–Gries summaries of the join column, swept over skew and over the number of counters. A handful of counters removes a regret of 243.9 at high skew; at an exponent of one half 256 counters remove nothing and 512 are needed, because the sum of squared frequencies no longer has a small set of values carrying it.

trusts the estimateinsured ×2insured ×8always the index11.5235expected regret, logarithmic · label: worst within three standard deviationsrho 14.42.51.11.0rho 215.17.82.22.0rho 413.57.54.04.0rho 1616.016.016.016.0σ = 1.5, median error e^-1, 65,536 rowsexact over the error distribution

What insurance against an estimate costs

Four planners choosing between an index and a scan on estimates wrong by a log-normal factor, priced exactly over the error distribution. Insurance that shifts the crossing is free and halves the tail at a small read ratio, costs a third of the expected regret at a moderate one when estimates run low, and buys nothing at a large one — and when estimates run high it lowers the expected regret too.

1M2M4M16M64Mmean run length, in memoriesrandom33 runssorted1 runreversed64 runssorted, 1% arriving late2 runssorted, 10% arriving late7 runs262,144 records, 4,096 in memorydashed: two memories

Runs twice as long as memory

Replacement selection measured against loading, sorting and storing memory-sized runs for an external merge sort. Runs average two memories on random input, one run on sorted input and exactly one memory on reversed input; halving the runs saves a merge pass only in narrow windows of file size, while nearly sorted input collapses the run count and with it the merge.

0%25%50%75%100%ln 2mean leaf fillrandom, even splits2,906 leavesrandom, rightmost-split rule2,949 leavesascending, even splits3,971 leavesascending, rightmost-split rule2,048 leavesdescending, even splits4,095 leavesdescending, rightmost-split rule4,095 leavesbulk-loaded from sorted keys2,048 leaves131,072 keys, leaves of 64each bar names its rule

The keys that arrive late

A B+-tree with real node splits built from the same keys in several arrival orders, under even splits and under the rightmost-split rule, beside a tree bulk-loaded from sorted keys. Leaf fill runs from 50% to 100% and the leaf count by a factor of two; random insertion settles near ln 2; and one per cent of late keys in an ascending stream removes the whole benefit of the rightmost-split rule.

12481632641282561executed queries the fit sawexpected regrettrusting the estimatefitted from the queriesthe best divisor, 1.5ρ = 4, σ = 1.5, 120 fits a pointlower is better

What a planner pays to find out what to pay

The insurance divisor a query planner applies to its own row estimates, fitted from executed queries rather than given, measured in expected and worst regret against the number of observations — and across a plane of read ratio and error spread where learning ranges from paying at once to never paying.

50%60%70%80%90%100%0%1%2%5%10%25%50%share of keys arriving latemean leaf filleven splitsrightmost-split rulesibling first, two into threeln 2131,072 keys, leaves of 64late keys arrive at a random later point

The sibling a full leaf asks first

B*-tree redistribution at the leaves of a B+-tree, measured against even splits and the rightmost-split rule on random, ascending, descending and late-arriving key orders — with the extra sibling writes it costs counted per key.

01251025501002505000.00010.0010.010.1110100how far S's ranking is rotated from R'strue size ÷ estimatethe uniform estimate8 counters a side8 counters, using their silenceexactZipf 2, 8 counters a sideabove the line: the estimate is too low

A summary's silence is a bound, not a count

A three-way join whose two sides are skewed towards different values, swept from identical rankings to unrelated ones, with the uniform estimate, a Misra–Gries summary of each side, and a summary that also uses the values it does not hold — and why only one direction of error is correctable.

234681016110size ratioblock transfers · levelsa range of 100 keyslevelsan absent point lookup1,048,576 keys, 5 bits a keyfilters answer one of these two

The read a filter has no key for

Range queries over a log-structured store measured against the point lookups its Bloom filters were bought for, swept over the size ratio, the range's length and the filter's bits — and the size ratio a store should be tuned to once its queries are not all point lookups.

6080100how far a full leaf looks for room, in siblingsmean leaf fill, per cent12481664randomascendingdescendingascending, 1% late131,072 keys · leaves of 64 · fan-out 64a reach of 1 is the adjacent-sibling rule

A key passed along the row

Redistribution in a B+-tree of 131,072 keys widened from the adjacent siblings to a chain across the parent's children, at reaches of 1 to 64, on random, ascending, descending and nearly ascending insertion: the leaves' fill, the pages written per key, the trade between the two, and how far a key actually travels.

1.201.401.601.80executed queries the fit sawexpected regret248163264128256fitted spread75% bound95% bound99% boundtrusting the estimatethe best divisor, 1.5ρ = 4, σ = 1.5, 120 fits a pointlower is better

A planner that knows how sure it is

An insurance divisor set from a one-sided upper confidence bound on the fitted error spread, swept from no bound to 99%: expected regret and worst regret against the queries seen, the trade between them at a fixed sample, the divisor each spread justifies at three read ratios, nine settings where the bound helps or hurts, and how slowly the inflation switches itself off.

0%25%50%75%100%8101214161820222426283032bits of key prefix the filter is built onshare of the empty levels the filter skips83%72%64%46%ranges of 0.1 keysranges of 1 keyranges of 10 keysranges of 100 keys5 bits a key, 4 levels, 2,000 ranges eachdigits: the best length's share

The runs a range query can skip

A levelled store of 2^20 uniform keys in four levels, each carrying a real Bloom filter over b-bit key prefixes at five bits a key, measured against an oracle that skips exactly the empty levels: the share of the oracle each prefix length recovers for ranges of 0.1 to 100 keys, the transfers saved across range lengths, which levels are skippable, the same filter asked a point question, and one filter against two on a mixed workload.

2122232451015pages written per key insertedleaves in the finished tree, in hundreds1241664target 1target 2target 8fixed reach (digits:siblings)reach following the walks131,072 keys, leaves of 64, fan-out 64window of 64 overflows

A reach that follows the stream

A B+-tree of 131,072 keys whose redistribution reach doubles or halves every 64 overflows on the mean walk they made: its leaves and pages written against every fixed reach on random, ascending, descending and nearly ascending insertion; its position against the fixed frontier at six targets; two streams that change order halfway; how many insertions it takes to notice each change; and the target below which an ordered stream makes it thrash.

235810filter bits a key, averaged over the storetransfers a query3.804.204.605.00one length, even bitsa length each, even bitsa length and bits eachthe oraclemixed workload, 2^20 keys, four levelsdotted: the oracle

The small levels' share of a range filter

Range queries on a built log-structured store of 2^20 keys in four levels, with a Bloom filter over key prefixes on each: the best prefix length for each level alone and for each range length, where the gap between one shared length and a perfect range filter goes, what each level's transfers do as its filter gets more bits a key, the best division of a fixed memory among levels with a length chosen for each, and what that division does to lookups for absent keys.

456filter bits a key, over the whole storetransfers a range query258101216203216 to 24 bits, asked where it fits16 to 24 bits, asked at everylengthone length, chosen for five bitsone length, chosen for each memorythe oraclefour levels, 2^20 keysdotted: the oracle

The resolution a range filter can afford

Prefix filters at every length from 16 to 24 bits sharing each level's memory in a four-level store of 2^20 keys, a range asked at the longest length covering it with two prefixes and refined below every yes, or asked at every length from the coarsest, against one length a level: transfers a range query against filter memory, transfers and reads of empty levels by range length at five bits a key, the occupancy of each level's prefixes, and filter probes a query.

-0.20000.2000.4000.6000.8001filter bits a keymulti-resolution minus one length25810162032keys in 16 clustersuniform keyshalf the ranges in the gaps, half at the keysbelow zero: multi-resolution cheaper

One length for the gaps and the clusters

A four-level store of 2²⁰ keys drawn uniformly or from 65,536 down to 16 windows of key space covering a sixteenth of it, with range queries starting anywhere in key space, centred on stored keys, or half of each; one prefix length a level chosen for each store, workload and memory against a Bloom filter at every length from 12 to 24 bits asked from the coarsest down, every skip checked against the keys: how many coarse prefixes are empty, which design wins in each cell, the lengths each workload wants, what one length for a mixed workload gives up on each kind of range, and the crossing against memory.

-0.300-0.200-0.10000.1000.2000.300filter bits a keytransfers a query saved against one length a level41024the best pair a levelmulti-resolutionhalf the ranges in the gaps, half at the keysabove zero: cheaper than one length

Two lengths that do the work of eleven

A four-level store of 2²⁰ keys in 16 clusters, in 4 large and 64 small ones, or in 16 groups of 16, asked half with ranges anywhere in key space and half with ranges at stored keys, at 4, 10 and 24 bits a key: one prefix length a level, the multi-resolution filter at every length from 12 to 24 bits, and the best pair of lengths a level asked coarse first, each chosen for its store, workload and memory — the saving against memory, the cost by range length, where the memory goes, the three stores, the saving charged again on fresh queries, and the filter probes each design asks.

shuffled arrivals036925%50%75%100%one cluster at a time036925%50%75%100%share of the 2^20 keys inserteddark: chosen each write · olive: chosen once · orange: none · green: perfect10 bits a key; transfers a range querychosen once: 12 and 22 bits

The filter rebuilt with every write

The 2²⁰ keys of a sixteen-cluster store inserted one at a time into a levelled store with a 4,096-key buffer and size ratio four, shuffled or a cluster at a time, stopped at six points of the fill and charged on range queries half in the gaps and half at stored keys: a coarse-and-fine prefix pair chosen for each level at its last write against one pair chosen once, the transfers through the fill, where they fall level by level, every candidate pair on the smallest level, the pairs the levels chose, the gap between the two policies at two and ten bits a key, and the share of a perfect filter's saving captured at three memories.

50%60%70%80%90%100%the store's fill, share of its 1,048,576 keysshare of a perfect filter's saving captured13%25%38%50%75%100%a cluster at a time, dividedshuffled, divideda cluster at a time, evenshuffled, even2 bits a key on averagedashed: the same bits on every level

One bit a key, divided

A levelled store of 2^20 keys in sixteen clusters, filled by insertion shuffled or a cluster at a time, each level's range filter a pair of prefix lengths chosen from its keys when it is written, given a total of 0.5 to 4 bits a key either evenly or by the division that makes the store cheapest on one seed of queries, charged on another: the share of a perfect filter's saving captured through the fill; each level's cost on the full store; the bits a key each level is given against its size; each level's cost against its filter's bits; the share captured against the budget; and where the memory goes.

All essays