Two signals, two failure classes
The metrics table already stores everything both monitors need: rows and distinct_keys, one row per table per night. analytics.orders_daily at Bellwether carries about 12,000 rows on a weekday and about 45 percent of that at the weekend, which is the fact that decides the shape of the volume monitor before you write a line of it. Uniqueness is the other half of tonight, and it exists as a separate monitor for one reason: its failure mode is invisible to every other check in the set.
★ What you walk out with tonight. Two working monitors and the measured cost of getting the volume comparison wrong: a fixed plus-or-minus 30 percent band around 12,000 fires on all eight weekend nights in a 30-night window, which is eight false pages for zero catches, while the same-weekday median catches the partial load with zero. Plus the duplicate-rate query that is the only thing in the whole set that sees night 19.
LiveWhy a row count is not a number3 min▶
Twelve thousand rows. Is that fine? There is no answer to that question, and every volume monitor that gets muted was built by somebody who thought there was. The count only becomes a signal once you attach a comparison, and choosing the comparison is the design work. Three candidates come up every time:
- A fixed band. Cheap to write, needs no history, and wrong on any table with a weekly rhythm. Bellwether's is the ordinary case, not an unusual one: grocery delivery is quieter at the weekend and no single band holds both patterns while still being tight enough to catch a missing shard.
- The same weekday. Compares Tuesday against Tuesdays. Handles the weekly rhythm exactly, needs four weeks of history to be comfortable, and is the right default for anything driven by human behaviour.
- A robust band around the median. For tables with no weekly rhythm at all, where the useful question is only "is tonight unlike the recent past" and you want the estimate not to be dragged around by the incident you are trying to detect.
Bellwether's night 16 arrived with one of three source shards missing: 4,920 rows against a same-weekday median of 11,986, which is 59 percent short. The fixed band caught it too. The difference is that the fixed band also paged on eight quiet weekend nights on the way there, and by the time night 16 arrived the on-call had learned to expect the alert.
Self-studyWhat each of the two monitors can and cannot see3 min▶
Worth being explicit, because the temptation is to think of volume as a general-purpose health check and it is nothing of the kind.
| Failure | Volume sees it | Uniqueness sees it |
|---|---|---|
| A source shard never arrived | Yes, the count drops sharply | No, the surviving rows are clean |
| A merge key changed and rows duplicated | Only if the net count moves enough | Yes, directly |
| Duplicates added and other rows dropped | Frequently not, the two cancel | Yes, the rate moves regardless |
| The same correct rows loaded twice as a full replay | Yes, the count roughly doubles | Yes, every key is now duplicated |
| A column went null across every row | No, the count is unchanged | No, unless the key is the null column |
That last row is the honest boundary of tonight: a null-rate collapse leaves both of these monitors green, which is why distribution is a separate signal with its own session.
Volume: the comparison is the monitor
9 min livePlot the series before choosing the comparison. Thirty nights of orders_daily has a rhythm you can see from across the room, and the moment you can see it the fixed band stops looking like a reasonable simplification.
LiveThe fixed band, priced properly3 min▶
The band is 12,000 plus or minus 30 percent, so a floor of 8,400 and a ceiling of 15,600. A weekend night at about 5,400 rows is not near that floor, it is 36 percent below it, so every weekend night is an alert by construction. In a 30-night window that is eight false pages, and they buy nothing: night 16 at 4,920 rows is caught by the same-weekday comparison too.
Widening the band does not rescue it. To hold a weekend night inside the band you need a floor below 5,200, which means a band of roughly plus or minus 57 percent around 12,000, and a weekday night can then lose 6,000 rows without a peep. That is the trade in its clearest form: a band wide enough to be quiet is too wide to detect the thing you built it for.
The tell that you have the wrong comparison. Your false pages cluster. If every alert lands on a Saturday, or at month end, or on the first working day after a holiday, the monitor has discovered a real pattern in your business and is reporting it as a fault. Move the pattern into the comparison rather than into an exclusion list.
LiveThe same-weekday median, and why median3 min▶
Compare tonight against the median of the last four same weekdays, and alert outside plus or minus 25 percent. On Bellwether's history that monitor produces zero false pages in 30 nights and catches night 16 with the sentence 4920 rows vs a same-weekday median of 11986, -59 percent, which is a message somebody can act on without opening anything.
Median rather than mean, for a reason that matters more than it sounds. Your history contains the incidents you are trying to detect. A mean of four values is moved by roughly a quarter of any outlier in the window, so the night after a partial load your comparison point has dropped and your threshold has quietly loosened exactly when you need it tight. A median of four values is unmoved by one outlier at either extreme. The property you want in a monitor is that a past incident does not raise the bar for detecting the next one.
- Four same weekdays is four weeks of calendar, which is long enough to be stable and short enough that a real change in the business washes through within a month.
- Twenty-five percent is wide enough to absorb ordinary week-to-week movement on this table and tight enough that a missing shard of any size clears it. Set yours from your own spread, not from this page.
- Both directions. A count 40 percent above the median is a duplicate replay or a backfill running into today's partition. Firing only on the low side is the most common half-built volume monitor.
- Guard the cold start. With fewer than two same weekdays in history the monitor must return "not enough history" rather than a comparison against one night.
Self-studyRobust bands with MAD, for tables with no rhythm4 min▶
Plenty of tables have no weekly pattern: a machine-generated event stream, a reference table, a slowly growing dimension. There the same-weekday comparison throws away three quarters of your history for nothing, and what you want is a band around the recent median that is not dragged around by outliers.
Median absolute deviation is the standard tool. Take the median of the series, take the absolute deviation of every point from it, take the median of those. Multiply by 1.4826 and you have a robust stand-in for a standard deviation on roughly normal data, which lets you keep thinking in familiar multiples.
Then band at the median plus or minus three times sd_robust. Two cautions. On a strongly seasonal table this is the wrong tool and will simply widen until it holds the weekend, so check for rhythm first. And on a table with genuinely tiny variance the MAD can collapse towards zero, which makes the band absurdly tight; floor it at some absolute minimum that means something in the units of the table, exactly as a percentage floor is used on a null-rate monitor.
The failure this avoids is well worth seeing once. Set a mean-plus-3sd band on 30 nights that include one 60-percent-short night, and the outlier both drops the mean and inflates the standard deviation, so the lower bound moves down twice. The band that was supposed to be tightened by the incident is wider afterwards than it was before.
Uniqueness: the failure that leaves the row count healthy
8 min liveOn Bellwether's night 19 a merge key changed upstream. The duplicate rate went from 1.0 to 8.4 percent and the row count stayed normal, so the pipeline reported success, the freshness check passed and the volume monitor passed. Nothing in the set saw it except a rate that nobody had built yet.
LiveA rate, not an assertion4 min▶
The duplicate rate is 1 - count(distinct key) / count(*), and on a large table it is a better monitor than a hard uniqueness assertion for three reasons that all show up in the first month.
- It degrades gracefully. A hard assertion has two states. A rate has a history, so you can see 0.6 percent creeping to 1.4 percent over a fortnight and fix the cause before it is an incident. A pass-or-fail check gives you no warning at all and then a build failure.
- It gives you a sentence. "Duplicate rate 8.4 percent against a limit of 2.0, up from 1.0 last night" is a message that survives being forwarded to somebody who does not know the table. "unique_order_id failed" is a message that requires a query before anybody can act.
- It tolerates a known floor. Many real tables have a small, understood duplicate population: a replayed event, a soft-deleted row, a late correction. A hard assertion on such a table is either disabled or wrapped in an exclusion list that nobody maintains. A rate lets you set the threshold above the known floor and monitor the deviation from it.
Set the threshold from the history, the way you set the freshness threshold. On this table the clean nights sit between about 0.6 and 1.4 percent, so a 2.0 percent limit is above every clean night and far below the 8.4 percent of the incident. It fires once in 30 nights and that once is night 19.
LiveComposite keys and the grain question4 min▶
This is where most duplicate monitors are actually wrong, and the error is invisible because the monitor is green. Before you can measure uniqueness you have to answer one question about the table: what is one row? One order? One order line? One order line per warehouse per day? A duplicate monitor is only meaningful against the declared grain, and if the grain in your head differs from the grain in the table, the monitor measures nothing.
Run both rates side by side on any table you are unsure about. If dup_rate_order is 40 percent and dup_rate_grain is 0, the table is not one row per order and a monitor on order_id alone would page every single night until somebody muted it. If both are 0, one row is one order and the simple monitor is correct.
- Concatenate carefully. A naive
a || bmakes('ab', 'c')and('a', 'bc')collide. Use a separator that cannot occur in the values, and coalesce the nulls, or the whole key silently becomes null and the distinct count collapses. - Nulls in a key are not distinct in the way you expect.
count(distinct)ignores nulls entirely, so a key column that is 30 percent null produces a duplicate rate that looks alarming for the wrong reason. Monitor the key's null rate alongside its duplicate rate. - Write the grain down next to the table. One sentence in the model's documentation. This is the single cheapest piece of documentation in a warehouse and the one most often missing.
Self-studyThe dual failure: duplicated and dropped at once4 min▶
The nastiest version of this failure is the one where a merge duplicates some rows and drops others, so the net row count barely moves. It is common because it has a single cause: a join key that changed cardinality upstream will both fan out the rows that now match several times and lose the rows that now match nothing.
What that does to your monitors is worth spelling out. Volume sees a net change of maybe one percent and passes. Freshness passes. The pipeline passes. The duplicate rate rises, because the fanned-out rows are genuinely duplicated at the declared grain, and it is the only signal that moves enough to cross a threshold.
The pair of numbers that identifies it. Store rows and distinct_keys separately, never just the rate. When the rate rises you then want to know which of the two moved: distinct keys falling while rows hold steady is a fan-out, and both falling together is a fan-out plus a drop. That distinction is the difference between a re-run fixing it and a re-run making it worse.
Two monitors that catch two different failures
★ 20 min · everyone buildsFive steps. Build the same-weekday monitor, build the fixed band beside it so you can count its pages yourself rather than take the number on trust, build the duplicate rate, run all three over the history, then write down the evidence for each threshold.
Step 1. The same-weekday median. Four weeks back gives up to four same weekdays. As with the freshness percentile, a moving median is awkward as a windowed aggregate in portable SQL, so join the metrics table to itself on weekday and date range and aggregate.
Step 2. Turn it into a monitor with a tolerance and a cold-start guard. Save step 1 as a view called weekday_history. Both directions, 25 percent, and a refusal to compare against a single night of history.
Night 16 comes out as 4920 rows vs a same-weekday median of 11986, -59 percent. Every other night in the 30 is inside the tolerance, so this monitor costs zero false pages.
Step 3. Build the fixed band beside it and count its pages. Do not take the eight on trust; the point of running it is that you see which nights they are.
Two rows come back: weekend, 8 pages, and weekday, 1 page. All eight weekend nights fire, and the single weekday page is night 16, which the same-weekday monitor also caught. Eight false pages for zero additional catches, in one query you can show anybody. Drop the group by and read the night numbers if you want to see them individually.
Step 4. The duplicate rate. Straight out of the two columns the metrics table already stores, with a threshold set above every clean night.
One night fires: night 19, at 8.4 percent against a 2.0 percent limit, up from 1.0 percent. Look at that night's other columns while you are there. Rows are normal, lateness is normal, the column count is unchanged. This is the whole argument for uniqueness being its own monitor rather than a footnote on volume.
Step 5. Run all three over the full history together. Same-weekday volume: 1 catch, 0 false pages. Fixed band: 1 catch, 8 false pages. Duplicate rate: 1 catch, 0 false pages. Two monitors, two catches, no noise, and one alternative version of the volume monitor that costs eight pages for nothing.
Step 6. Write the evidence line for each threshold. Four fields: the comparison, the tolerance, the widest clean deviation in your history, and the pages it would have sent. For this table: same weekday median, 25 percent, widest clean deviation well inside it, zero pages. Duplicate rate, 2.0 percent, clean nights between 0.6 and 1.4 percent, one page and it was real.
That line is what makes a threshold reviewable. A threshold with no recorded evidence is indistinguishable from a threshold somebody invented, and after two staff changes there is nobody left who can tell you which one it was.
Set thresholds from history, not from a feeling. Every number on this page came out of a query over recorded nights: 25 percent because the clean deviations are far inside it, 2.0 percent because the clean nights top out at 1.4. If you cannot produce the query that justifies a threshold, you have a preference rather than a monitor, and preferences do not survive their first argument at 07:00.
Before session 4
30 min- Plot 30 nights of row counts for your table and say out loud whether it has a weekly rhythm. That single answer picks between the same-weekday median and a robust MAD band, and it takes one chart.
- Backtest whichever you picked over the history you have and count the pages. If it would have fired more than about once a week, the tolerance is wrong, not the method.
- Answer the grain question in writing for one table: what is one row? Then run the two duplicate rates side by side and check that the answer in your head matches the answer in the data.
- Put the duplicate-rate monitor on the key of that table with a threshold above every clean night in your recorded history, and note the highest clean value you saw.
- Check whether your metrics table stores
rowsanddistinct_keysas separate columns rather than only the derived rate. If it stores only the rate, fix that tonight; the missing count is the one you will want during an incident.
Three questions
Bellwether's weekend volume is about 45 percent of a weekday. A fixed plus-or-minus 30 percent band around 12,000 rows runs over a 30-night window. What does it cost?
The floor is 8,400 and a weekend night is about 5,400, which is 36 percent below it, so every weekend night alerts by construction. Night 16 is caught by the same-weekday median too, so the eight pages buy nothing.
Why compare against the median of the last four same weekdays rather than the mean of them?
After a partial load, a mean-based comparison point has dropped, so the threshold has loosened exactly when you need it tight. A past incident must not raise the bar for detecting the next one.
On night 19 a merge key changed upstream. The duplicate rate went from 1.0 to 8.4 percent and the row count stayed normal. Which checks pass?
A key change can duplicate some rows and drop others, landing within a percent of a normal night. That is the failure class uniqueness exists for, and it is why the rate is stored separately from the count.