cswork / libraryOpen practice workspace

Articles

Bigtable Interview Questions: Row Keys, Hotspots, and Time-Series Access

Design Bigtable row keys for time-series reads while avoiding timestamp hotspots; compare reverse time, buckets, sharding, and measured trade-offs.

A Bigtable interview question that asks “What row key would you use?” is incomplete until you know the reads and writes. timestamp#device makes a global time scan look neat but can concentrate sequential writes. device#timestamp makes one device's history contiguous but does not automatically serve a fleet-wide time query. Adding a hash may spread work while forcing readers to fan out. A strong answer makes those costs visible before choosing a key.

This guide works through an original sensor-data design with explicit access patterns, candidate row keys, hotspot failure modes, and validation steps. Google Cloud's Bigtable schema guidance is the source for product behavior. The workload and design comparison here are illustrative, not a benchmark or a report that a particular company asks this exact question. For broader systems practice, Design a Metrics Collection System provides an adjacent prompt.

Ask for the query contract first

Suppose two million sensors write temperature and vibration readings every minute. Product users most often request a single sensor's last 24 hours, sometimes its latest twenty readings. Operators occasionally request all sensors in one region for a ten-minute incident window. Retention is 90 days. A small number of sensors are abnormally chatty and send many events per second. The design must make a choice: optimize the common single-sensor reads while keeping writes distributed, or optimize the rare regional scan at greater cost elsewhere.

Start by ranking those access patterns, not by reciting “Bigtable is NoSQL.” Google Cloud says schema design is driven primarily by planned reads and that row-range reads are fastest when keys group relevant data under useful prefixes. A Bigtable table's primary index is its row key; there is no general relational join to rescue a key that does not support a query. The key is sorted lexicographically, so the position of each component determines which prefix and range scans are efficient.

Clarify a few more requirements before drawing a schema. Are late events common? Does “latest” mean event time or ingestion time? Can a sensor be renamed or moved between regions? Is a ten-minute regional query interactive or a batch diagnostic? How large can one event be? Must an update be atomic across sensors, or only within one row? These answers determine whether a single table is sufficient and how to handle secondary access paths.

This is the interview thesis: a row key is an index and a placement decision at the same time. It affects locality, scan size, and the concentration of writes. You cannot evaluate it by readability alone.

Compare three plausible row-key layouts

Use fixed-width, sortable timestamp encoding in this thought exercise, and a stable opaque sensor ID. The # delimiter is illustrative. Do not place private device-owner data in the key: Bigtable documentation cautions that identifiers in row keys can appear in logs and tooling.

Candidate keyEfficient readWeakness to name
event_time#sensor_idAll events across the fleet near one time, if write pattern toleratedSequential timestamps lead writes into a narrow key range; single-sensor history is scattered
sensor_id#event_timeRange of readings for one sensorFleet-wide time window needs many sensor-prefix reads or another index; a very hot sensor can still concentrate traffic
region#sensor_id#event_timeRegion-and-sensor historyRegion-wide time window is not contiguous across sensors; region changes complicate key identity

The second key is the initial favorite because the highest-volume read is by sensor and time. To fetch sensor S42 over a date interval, construct start and end keys under S42#. To get the latest twenty rows with ascending timestamps, however, you may need an efficient reverse range strategy or an alternative key. A lexicographic range over S42# cannot magically return descending time without the appropriate ordering or client behavior.

Google's schema best practices explicitly warn against starting row keys with a timestamp because sequential writes can hotspot. They also note that sensor#timestamp-style keys can be useful for time ranges but can still hotspot when writes concentrate. “Put the timestamp last” is therefore a starting point, not a guarantee.

What does a reversed timestamp solve?

If most reads ask for newest-first values for one sensor, consider sensor_id#reverse_time, where reverse_time is a fixed-width value such as a maximum timestamp minus the event timestamp. The newest event sorts first within that sensor prefix. Google documents reversed timestamps as a pattern for latest-first access, while warning not to put a reversed timestamp at the start of the key.

Be exact about the trade-off. Reverse time changes ordering, not the fact that one sensor's adjacent writes fall into a nearby key range. It helps the latest-twenty read but may complicate forward time scans and date-range bounds. Write a small key-order example before claiming the implementation works:

S42#R(10:03)  -> sorts before S42#R(10:02)
S42#R(10:02)  -> sorts before S42#R(10:01)

Here R(t) is a fixed-width inverse timestamp encoding; the strings are a schematic, not literal production keys. If your timestamps have variable string width or inconsistent time zones, the lexicographic order can surprise you. Use one precise UTC encoding and test generated keys at a minute, day, and year boundary.

Late-arriving data introduces another choice. If the key uses event time, a late event lands among older rows, which supports event-time retrieval but means writes are not purely append-like. If the key uses ingestion time, ingestion scans are easy but an event-time query may miss or misorder late data. The interview answer should define which clock “latest” means before choosing either.

Time buckets versus one row per event

Bigtable's time-series design guide describes both time-bucket rows and single-timestamp rows. A bucket might be sensor_id#2026-09-24T10, with readings added as cells or columns within an hour. That can compress and read a sensor-hour efficiently. But a bucket is not infinitely elastic: very chatty sensors can create a frequently updated row or exceed recommended row size. Google notes a recommended maximum of 100 MB per row in the time-series guidance and recommends choosing bucket width based on workload and size.

One row per event, such as sensor_id#metric#event_time#event_id, avoids a single ever-growing row and gives an unbounded sequence of readings. It can use more rows and may have different compression or read trade-offs. Include an event ID or another tie-breaker if two events can share the same sensor, metric, and timestamp; row keys must be unique. The tie-breaker also requires a clear duplicate policy so retries do not silently create multiple logical events.

For cells with multiple versions, set garbage-collection rules deliberately. A 90-day business retention requirement does not materialize because the row key has a date. Decide whether retention is enforced through cell GC, row-range deletion, lifecycle jobs, or a combination, and test what remains readable. Bigtable's time-series guide explicitly calls out GC rules for patterns that append versions to a column.

Do not claim bucketed rows are universally faster. The answer depends on actual read width, event rate, row growth, and update concentration. If the task says sensors emit once per minute, an hourly bucket may be reasonable; if one sensor emits thousands of times per second, use a smaller bucket or event rows and measure.

Handle hotspots without sacrificing every read

A hotspot is concentrated access to a small key space or tablet that harms latency. Two patterns in this exercise deserve attention: a timestamp-first global write frontier, and one exceptionally chatty sensor under a sensor-first key. Google provides hot-tablet inspection guidance and Key Visualizer tooling for diagnosing the problem. In an interview, state what evidence would confirm the suspected hotspot rather than asserting one from key shape alone.

Salting or bucketing can spread writes, but the salt function matters. If you prefix hash(sensor_id) % 16, every event from one hot sensor still lands in one salt bucket. That may distribute many sensors across tablets, but it does not split a single hot sensor's traffic. To shard one hot sensor, the shard choice must vary across its events, such as an event-ID-derived bucket. Then reading that sensor's history requires scanning and merging multiple shard ranges, and a latest-N query needs a top-N merge. Google's key-salting discussion explains the balance between distribution and retrieval.

Do not salt preemptively. With two million reasonably active sensors, a simple sensor-prefix design may distribute sufficiently; only measurement reveals whether the exceptional hot sensors violate latency goals. Start with expected write rates and a load test, inspect tablet distribution, and add shards to a proven hot path. Otherwise you pay read fan-out and operational complexity for a problem you may not have.

The rare region-wide ten-minute query is another cost. A sensor-prefix primary table cannot serve it as one contiguous range. Options include a separate derived table organized for region/time, an analytical export, or a bounded fan-out across known sensors. Each has freshness, write-amplification, and maintenance consequences. Google notes continuous materialized views as a secondary-index mechanism, but applicability depends on the query and product constraints; do not promise it solves every multidimensional access pattern.

Show how you would test the design

A convincing interview answer ends with a verification plan. First, generate representative row keys and sort them as bytes. Show that one sensor's time interval is contiguous and that latest-first ordering actually works if using reverse time. Second, estimate rows or cells per sensor per day, row size under the hottest plausible sensor, and scan fan-out for the region query. Third, load-test with the expected skew rather than uniform fake IDs only. Fourth, observe p95/p99 reads, write latency, hot tablets, and scan bytes. Fifth, inject late events, duplicate timestamps, retries, and a sensor region move.

Include a failure case that could falsify your choice: “If a single sensor drives a hot tablet even with the chosen key, I will compare event-level sharding with a targeted derived table and measure the added read fan-out.” That is better than “Bigtable scales automatically.” Product documentation provides design principles; it does not promise a particular throughput or latency for this invented workload.

The concise answer is: “I will optimize the dominant sensor-and-time range read with a sensor-first key, consider reverse time for latest-first access, and avoid timestamp-first writes. I will choose bucketed versus event rows from row-size and update-rate estimates. I will verify hot-sensor behavior with load tests and tablet diagnostics. For the rare region-time query, I will budget a separate access path or accept a measured fan-out.”

Related practice questions

QuestionTransferable design skill
Design a Metrics Collection SystemDefine write shape and retention
Design an Incremental Rolling-Metrics Data PipelineHandle time windows and updates
Diagnose why a scaled system became slowProve a hotspot from evidence
Search Recorded Metrics by Name, Tags, and RecencyDesign access paths for competing queries
Design a Low-Latency Metrics and Alerting PlatformConnect freshness, latency, and storage choices

Sources and further reading