skip to content

Cardinality & Key Size

How many distinct keys a design creates and what each costs before its value is counted, including the key long enough to outweigh the thing it points at.

on this pageshow

questions

4

A key scheme in an in-memory store mints one entry per user per day per field. How do you size it before shipping?

level: middleimportance: must knowfreq 62%

answer

  1. read the template as a product
  2. count first, bytes second
  3. chosen bytes are a floor, not the total
  4. ask which factor has no ceiling
  5. state the figure with its assumptions

basics

~20 s

Multiply the factors out to a distinct-key count, then price each entry as key bytes plus value bytes and multiply again. Compare the result with the tier's budget, and identify which factor is unbounded before arguing about the bytes.

solid answer

~40 s

Do the arithmetic on paper first. The **distinct-key count** is the product of the template's factors: users, times days of history kept, times fields per user per day. Then price one entry: the bytes of the key string plus the bytes of the value, knowing the real figure per entry is larger because every entry carries fixed bookkeeping on top — measure that on your store rather than guessing it. Multiply count by bytes and compare with the memory you have. Then read the factors again and ask which one has no upper bound: users grow with the business, fields are fixed by the design, and days accumulate forever unless a lifetime on the entry bounds them. Sizing that ignores the unbounded factor produces a number that is correct today and wrong next quarter.

go deeper

for a junior

Remember the order: count the keys the scheme creates before you talk about memory. The count is the product of the factors in the key template, and the key string costs bytes just as the value does.

for a middle

Be able to run it end to end: factors multiplied out, bytes per entry priced, product compared against the budget, and the unbounded factor named. Say out loud that chosen bytes are a floor.

for a senior

Show that you size against the busiest node and the next year's multiplier, and that you verified the per-entry cost by measurement on your own tier rather than carrying a number over from a previous one.

for a principal

The judgment is whether the scheme should exist. If the figure only works given a retention rule nobody owns, the decision is a bounded design or a different store, not a bigger tier.

Sizing a key scheme is arithmetic, and the reason it is worth doing on paper is that the store will never do it for you: it accepts each write on its own merits and the design is visible only in the total. ## Step one: multiply the template out Read the key template as a product of factors. "One entry per user per day per field" is three factors, and each one is a number you can obtain from someone: - **users** — from the business, plus a growth assumption you state out loud; - **days of history retained** — from the requirement, not from the code, and often nobody has decided it; - **fields per user per day** — from the design; this one is fixed and small. The product is the standing **distinct-key count**: how many separate keys exist at any moment once the scheme reaches steady state. Keep it separate from the *rate*, which is keys added per day — you need both, because the rate tells you how fast a wrong assumption becomes an incident. ## Step two: price one entry, honestly The bytes you chose are the key string plus the value. Both are real: the key is stored, not metadata that lives somewhere free. But the bytes you chose are a floor, not the answer. Every entry in a store of this class carries fixed bookkeeping beyond its own bytes — how much varies between stores, and by enough that a figure carried over from one store is worthless on another. The way to get it is to measure: write a representative sample of real entries at production sizes into a tier you can inspect, and read the difference. That per-entry cost is its own subject; for the arithmetic here, treat it as a measured constant you add. ## Step three: find the unbounded factor | Factor | Bounded by | What it does over time | |---|---|---| | users | the business | grows, slowly and predictably | | fields per user per day | the design | fixed unless the design changes | | days retained | nothing, by default | grows forever until something removes entries | The third row is where most of these schemes fail. A per-day key is a new key every day, permanently, unless each entry carries a deadline after which the store removes it, or a job removes them. The lifetime is the other lever available here and how those deadlines behave is a separate subject; the arithmetic point is simply that the days factor is a decision someone has to make, and if nobody makes it the factor is infinity. ## Step four: consider the other shape, with the precondition attached The count is a consequence of how many keys the design mints, so the sharpest lever is to mint fewer. Folding the four per-day fields under one key — a single entry per user per day, holding the fields inside it — divides the distinct-key count by four and removes three copies of the key text. That move has a precondition that is easy to assert and wrong on much of this class of store. It is worth having only where the server understands the value as a structure and can read or change part of it; on a store where a value is **opaque bytes the server only hands back**, one entry holding four fields means every change to any field is a full read, modify and write of the whole value, and every read of one field pulls all four across the network. What the structure can do is another subject entirely — here it is only a premise that decides whether the folding is a saving or a tax. ## Step five: state the answer as a range with assumptions The output of this exercise is not one number. It is a figure, the assumptions it rests on, and the factor that will invalidate it: 1. "At two million users, ninety days retained and four fields, the scheme stands at seven hundred and twenty million entries." 2. "At the bytes we chose, that is roughly forty gigabytes before per-entry bookkeeping, which we measured at our sizes and added." 3. "Days retained is the unbounded factor, and today nothing bounds it." 4. "At five million users the same scheme is two and a half times this figure, and the answer is a different design, not more memory." An engineer who can produce those four lines before shipping has done the work this subject exists for. ## The whole method: multiply the factors, then price the bytes you chose. The figure counts chosen bytes only; the fixed bookkeeping each entry carries is measured on your own tier and added on top ``` users 2,000,000 days of history retained 90 fields per user per day 4 --------------------------------------------- distinct-key count 2,000,000 x 90 x 4 = 720,000,000 entries key bytes (template plus identifiers) ~48 value bytes (a short number) ~8 --------------------------------------------- chosen bytes 720,000,000 x 56 bytes = about 40 gigabytes keys added per day 2,000,000 x 4 = 8,000,000 unbounded factor days retained ```

  • Which factor do you attack first when the figure comes out too large?
    The unbounded one, because it is the only factor that makes the answer wrong rather than merely big. Bound the retention — attach a lifetime to each entry so the store removes it, or narrow the granularity from per-day to per-week. Only then consider folding fields or shortening the key, which scale the figure down by a constant rather than capping it.
  • Your estimate says forty gigabytes and the tier has thirty-two. What do you check before buying memory?
    That the per-entry figure is measured rather than assumed, because the fixed bookkeeping each entry carries varies enough between stores to move the total by a large fraction. Write a representative sample at production sizes and read the real difference. Check the retention assumption too: an unbounded days factor means any memory you buy is a delay, not a fix.
  • Does the same arithmetic hold when the keyspace is split across nodes?
    The count does: it is the sum across nodes, and the design produces the same total however it is spread. What changes is the comparison — each node has its own memory, so an uneven template can exhaust one node while the sum still looks affordable. Size against the busiest node, not the average. Assigning keys to nodes is a separate subject.

saying these in an interview costs you the question

  • Estimates memory without ever computing the key count
  • Prices only the value and treats the key string as free
  • Treats chosen bytes as the whole per-entry cost
  • Sizes for today's users with no growth assumption stated
  • Assumes folding fields into one entry is always a saving
  • Confuses keys written per day with the standing total
open as a page

A service creates a new key in an in-memory store on every request and deletes none. What does the store do about that growth?

level: juniorimportance: should knowfreq 55%

basics

~20 s

Nothing. Each write is individually valid and there is no schema against which a key count could be judged, so a key-minting design shows up only in the total entry count and the memory used, never in a refused write.

open as a page

An in-memory store holds a one-byte flag under a ninety-character key, forty million times over. What is that ratio costing?

level: middleimportance: should knowfreq 48%

basics

~20 s

The addressing has become the data: about 3.6 gigabytes of key text against 40 megabytes of payload. Keys are stored bytes, they travel on every call, and at high counts a key can far outweigh what it addresses.

open as a page

A team wants to cut key bytes in an in-memory store by hashing each long key to a short fixed-width string. What does that trade?

level: seniorimportance: should knowfreq 44%

basics

~20 s

It trades legibility and a small chance of silent collision for a saving of exactly the bytes removed times the distinct-key count. Compute that product first: a collision here is one caller reading another's value, unreported.

open as a page