advanced24 min studyLesson 284 in Engineering

Nested-loop, hash, and merge joins

Choose a join algorithm from predicate support, input size, ordering, skew, and memory instead of ranking operator names universally.

On this page

What you’ll understand

  • Compare naïve and indexed nested-loop work.
  • Separate hash-build, probe, output, and spill costs.
  • Explain when sorted inputs let a merge join avoid an additional sort.

A logical join specifies matching rows; a physical join supplies the mechanism. Nested loops, hashing, and merging expose different opportunities and failure modes. Their practical comparison must include the number and width of input rows, available indexes or ordering, supported predicates, duplicate groups, and the output itself. An algorithm cannot avoid producing an enormous required answer merely by having a favorable input-size bound.

Nested loops can mean repeated scans or selective probes

A naïve nested loop considers each outer row against every inner row, evaluating the join condition on every pair. It supports broad predicate forms but can perform a product of input sizes. An indexed nested loop is a different physical strategy: an outer key drives a lookup into the inner relation, so only candidate matching rows need inspection. This can be excellent for a small outer input and a selective usable index. Index traversal, random access, repeated keys, visibility checks, and the number of returned matches all affect its actual cost.

A row-count underestimate is especially dangerous when it turns a supposedly tiny outer input into thousands of repeated expensive lookups. Conversely, replacing every nested loop with hashing can force a large build and delay useful output for a query needing only a few rows. Establish what the loop rescans and whether it has a parameterized access path. The phrase nested loop alone does not tell you whether the inner operation is a full table scan, a cached small relation, an index probe, or another complex subplan.

Cnaive≈mncθ,Cindexed≈mcprobe+kcemitC_{\rm naive}\approx mn c_\theta,\qquad C_{\rm indexed}\approx m c_{\rm probe}+k c_{\rm emit}
m and n count outer and inner rows, k counts result pairs, and c values are comparable abstract cost units per modeled operation. The first model counts every candidate pair; the second assumes a usable selective index and hides candidate-check and cache costs inside probe cost.↔ Scroll wide equations horizontally.

Hashing changes access, not the required multiplicity

For a supported equality condition, a hash join builds a table from one input and probes it with the other. Good hash behavior and an in-memory build can make expected input processing roughly linear, plus output work. Build size is a byte-and-overhead question, not merely a row-count comparison. A narrower larger relation can sometimes be cheaper to build than a smaller wide one. A hash collision requires an equality check, and nonmatching extra join conditions still need evaluation; hashing does not establish SQL equality by itself.

Skew creates two distinct risks. Many rows in one bucket can hurt lookup or partition balance, while a key repeated on both sides genuinely requires a product of matching rows. The second cost is unavoidable output, not just a bad hash function. If the build does not fit its available memory, partitioning and temporary storage can add substantial work. Null handling and outer-join bookkeeping also depend on the requested semantics. Use a complete plan to identify the actual build side and inspect observed batches or spill evidence before calling a hash join cheap.

Chash≈(m+n)ch+kcemitC_{\rm hash}\approx (m+n)c_h+k c_{\rm emit}
This expected in-memory teaching model counts build and probe input rows plus k output pairs. It assumes a suitable hashable equality condition, controlled collision cost, and sufficient memory; skew, residual predicates, partitioning, and storage spills can add work. Costs are abstract units, not seconds.↔ Scroll wide equations horizontally.

Merge joins exploit compatible order

A merge join advances through inputs ordered compatibly with the join comparison, matching equal key groups. If the order is already available, it can avoid building a hash table or sorting those inputs again. If order must be created, sorting belongs in the comparison. Duplicates can require revisiting or retaining an equal-key group and still emit many pairs. Do not confuse linear movement through sorted keys with a promise of linear total output when a large matching group exists. Collation, comparison semantics, and supported merge conditions determine whether the order is usable.

Use the cache lab to inspect a narrow reuse effect relevant to repeated probes. Reset, set both capacity C=4 and stride s=4, predict twelve hits in the initial sixteen requests, then Play or Step. Separately Reset, set both C=4 and s=1, predict zero initial hits, then Play or Step. The first fixed modulo-sixteen trace cycles over four addresses; the second cycles over sixteen. This is an exact toy LRU trace, not a join, an index, or a processor benchmark. It illustrates why probe locality belongs in a cost argument without selecting the winning SQL algorithm.

Separate candidate checks from input processing

An inner equality join has 1,000 outer rows and 5,000 inner rows. Each outer row matches exactly one inner row. Compare a naïve full-scan nested loop with a hypothetical in-memory hash join using one abstract unit per input row and one per emitted result.

  1. The naïve loop checks 1,000 × 5,000 = 5,000,000 candidate pairs. Its 1,000 emitted rows are separate result work rather than a reduction of the candidate count.

  2. The hash teaching model processes 5,000 build rows and 1,000 probe rows, totaling 6,000 input units. Add 1,000 result units for a modeled total of 7,000.

  3. An indexed nested loop is not priced by the five-million-pair figure. If a suitable index exists, its own probe, candidate, and result costs must be modeled; the given numbers do not establish its measured latency or whether it beats the hash plan.

The result

The calculation explains why full rescanning can be expensive while preserving room for a different indexed-loop strategy to win.

Explore the model

Interactive lab

Interactive lab · cache

Probe reuse is one input to a join cost

Reset, set both C=4 and s=4, predict twelve hits among the initial sixteen modulo-sixteen requests, then Play or Step. Separately Reset, set both C=4 and s=1, predict zero initial hits, then Play or Step. This fixed fully associative LRU stream is neither a join nor a real index-cache trace.

Probe reuse is one input to a join costA fully associative LRU cache starts empty and requests address (i·s) mod 16. Hits move an address to the newest position; misses evict the oldest when full. Playback starts with 16 requests and adds two per second, capped at 4096 explicitly simulated requests. This toy stream is not a processor-cache benchmark. Current readings: Hits / requests: 0 / 16; Hit rate: 0%; Address-stream period: 16 addresses. All parameters are adjustable with the labeled controls below.Fully associative LRU cache after 16 deterministic requests: 0 hits and 16 misses.Most recent 16 requestsaddress = i × 3 mod 160M3M6M9M12M15M2M5M8M11M14M1M4M7M10M13MCurrent cache order · oldest → newest471013Latest address 13 · miss: inserted as newestToy address stream · period 16 · starts empty
Cached addressMiss / evictionMost recent request
Hits / requests
0 / 16
Hit rate
0%
Address-stream period
16 addresses
t = 0 s

A fully associative LRU cache starts empty and requests address (i·s) mod 16. Hits move an address to the newest position; misses evict the oldest when full. Playback starts with 16 requests and adds two per second, capped at 4096 explicitly simulated requests. This toy stream is not a processor-cache benchmark. 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 forRepeated access to a fitting set differs from a larger cycle, but the toy trace cannot choose a SQL join algorithm.

Check your understanding

Why can a hash join with repeated key k on both sides remain expensive even with perfect hashing?

Try it yourself

Two already compatibly sorted inputs contain 100 and 200 copies of the same join key. An inner equality join has no additional filter. How many result rows does this group require, and which cost does that expose?

Take a moment to make a prediction or work it out on paper. Open a hint when you need one.

Give me a hint

Count matching pairs, not just distinct keys or input rows.

Compare with the solution

The group requires 100×200=20,000 rows. Even though merge processing can advance through sorted keys efficiently, emission and duplicate-group handling must account for those pairs. This is required multiplicity, not evidence that the inputs should have been deduplicated or that sorting was ineffective.

Take it with you

  • Inspect the actual inner access path before pricing a nested loop.
  • Hash build memory, skew, and required output all matter.
  • Merge joins need compatible order, with any sorting and duplicate-group work included.

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.