skip to content

Chained-table lookups spike for one tenant while average load factor reads 0.7 — how do you diagnose it?

level: seniorimportance: should knowfreq 44%

answer

  1. The dashboard number is an average of something
  2. Averages hide the worst bucket entirely
  3. Look at the distribution, not the mean
  4. Ask whether more buckets would separate them
  5. Identical hash values survive every resize

basics

~20 s

Average load factor is a mean across buckets and hides skew. Measure the distribution — longest chain, not the mean — and check the key derivation: a hash that ignores the varying part of a key piles one tenant into one bucket.

solid answer

~50 s

The dashboard number is an average, and an average over buckets says nothing about the worst bucket. Chaining's expected-time bound assumes keys scatter uniformly; when they do not, one chain can hold most of a tenant's keys and lookups against it walk linearly while the mean stays near 0.7. So instrument the **distribution**: longest chain length, chain-length histogram, share of entries in the top bucket. Then look at the key derivation — a composite key hashed on a field that is constant per tenant, or a reduction that masks off bits the keys never vary, will collapse a whole tenant into one bucket. The critical diagnostic: if the offending keys share an *identical* hash value, growing the table does nothing, because they land together at any bucket count. That distinction tells you whether the fix is a better mix step or a different key.

go deeper

for a junior

Remember that a low load factor is an average across all buckets, so it can look perfectly healthy while one bucket holds a very long chain and lookups against it are slow.

for a middle

Explain why the mean cannot see skew and what to measure instead: longest chain, chain-length histogram, share of entries in the busiest bucket. Tie the slow slice back to how the key is hashed.

for a senior

Diagnose it end to end: bimodal latency correlated with a key attribute, green aggregate metrics, then the decisive test of whether the offending keys share an identical hash value or merely collide after reduction.

for a principal

Own the observability gap — decide which table-shape metrics a service exports by default, and weigh a key-derivation fix against its migration cost when the table cannot pause writes.

## Why the average lies A chained hash table's headline metric is its load factor, entries over buckets. It is the *mean* chain length. Under the uniform-hashing assumption the mean is a good summary because the distribution around it is tight. When that assumption fails, the mean becomes almost useless: entries can pile into a handful of buckets while the arithmetic mean sits comfortably below the resize threshold, so the table never even considers growing — and growing would not help anyway. Picture a multi-tenant service holding a table keyed by tenant identifier plus record identifier. One tenant is misconfigured and emits records whose keys differ only in a field the hash never reaches — say the key object's hash is derived from the tenant portion alone, or the reduction step masks the low bits and every one of that tenant's identifiers shares those bits. Every one of that tenant's records lands in the same bucket. The table now contains a chain thousands of nodes long, and a lookup against that tenant walks it. Meanwhile the other tenants are spread across the remaining buckets and the reported load factor reads 0.7. ## The symptom shape This failure has a recognizable fingerprint, and recognizing it is most of the interview answer: - Latency is **bimodal, not uniformly degraded** — most requests are fast, one slice is catastrophically slow. - The slow slice **correlates with a key attribute** (one tenant, one prefix, one region), not with time of day or table size. - Aggregate health metrics are **green**: load factor normal, memory normal, no errors. Correctness is unaffected; only latency moved. - Growing the table **does not fix it**, and may not even trigger, since the mean never crosses the threshold. ## How to confirm it Stop looking at the mean and measure the shape of the distribution. The three numbers that matter are the **longest chain**, the **chain-length histogram**, and the **fraction of entries in the busiest bucket**. A healthy table under uniform hashing at `alpha = 0.7` has a longest chain in the low single digits; a table whose longest chain holds thousands of entries is not a hash table any more, it is a linked list with an index in front of it. If you cannot instrument the table itself, the shape can be inferred: measure comparison counts or lookup latency grouped by key attribute, and the offending group separates immediately. ## The decisive distinction Once skew is confirmed, one question determines the fix: do the offending keys produce **identical hash values**, or merely values that *collide after reduction* into the current bucket count? - **Identical hash values.** Growing the bucket array is useless — identical values reduce to the same index at every table size, so the chain survives every resize intact. The problem is upstream, in how the key's hash is derived: it is ignoring the part of the key that actually varies. The fix is to include the distinguishing field, or to key the table differently. - **Distinct values that collide after reduction.** Here the values differ but the reduction throws away the bits that differ — for example masking to the low bits when the keys vary only in the high bits. A mixing step that diffuses high bits into low ones before the reduction, or a reduction that does not simply drop bits, separates them. This class *is* repaired by a better mix, and often by a different table size. Stating this distinction unprompted is what marks a senior answer. Most candidates propose "make the table bigger", which addresses only the second case and is worth nothing in the first. ## Why the table still returns correct answers Worth saying explicitly: nothing is broken. Chaining's correctness does not depend on distribution at all — a chain of ten thousand nodes returns exactly the right entry, just slowly. That is why this incident presents as a latency problem with no error signal, and why it can survive in production for a long time. It also means the mitigation is never urgent for correctness and always urgent for the tail-latency budget, which is a different conversation with a different owner. ## The lesson to carry Chaining converts bad key distribution into slow lookups rather than failures. That is a genuine robustness property — the gentle degradation is a feature — but it means the aggregate metric everyone watches is exactly the metric that cannot see the problem. If a service's latency depends on a hash table's chain lengths, then chain lengths, not load factor, are what belongs on the dashboard.

  • The skewed keys all produce the identical hash value. Does doubling the bucket count help?
    No. Reduction is a function of the hash value, so identical values map to the same bucket at every table size — the chain reassembles intact after every resize, and you have doubled memory for nothing. Only changing how the key's hash is derived, so it reflects the field that actually varies, separates them. This is the case where 'just grow the table' is pure waste.
  • Why did correctness stay perfect throughout the incident?
    Chaining's correctness does not depend on distribution. A bucket holding ten thousand entries still contains the right one, and the walk still compares full keys and finds it. Only the number of comparisons changed. That is why the failure surfaces as tail latency with no error rate, no alert, and no data loss — and why aggregate health checks stay green throughout.
  • What single metric would have caught this before the tenant complained?
    The longest chain length, or a chain-length histogram, exported alongside load factor. Under uniform hashing at a normal load factor the longest chain sits in the low single digits, so an alert on it firing at, say, fifty is both quiet in normal operation and immediate when a distribution collapses. Mean load factor cannot express this and never will.

saying these in an interview costs you the question

  • Concludes the table is healthy because load factor is low
  • Proposes resizing without checking whether hashes are identical
  • Assumes low average load factor implies short chains
  • Treats it as a correctness bug rather than a distribution problem
  • Watches only the mean and never the longest chain

context