Agreeing the grain before anybody builds a dashboard
Grain sounds like modelling jargon and it is the most practical decision in the project. It is simply the question of what a single row represents. An order, an order line, a shipment, a shipment line, or a daily summary of any of those. Getting it wrong is not a rounding issue. Quantities double, averages stop meaning anything, and every measure built on that table inherits the error silently. Nothing fails, and every number is slightly wrong in a direction nobody can predict.
The mistake usually arrives as an innocent request to add a column. Somebody asks for delivery date on an order level table, delivery actually happens per line, and the table quietly changes grain to accommodate the request. Every existing measure is now wrong in a way that is genuinely difficult to see, because the totals still look approximately right and only certain specific cases diverge from the source. Those cases are usually the large orders, which are precisely the ones somebody eventually checks by hand.
We write the grain down for each fact table, state what a row represents in language a business user can check, and then hold that line through the inevitable requests. Where a different grain is genuinely needed, it becomes a separate table rather than a compromise, because two correct tables cost far less over time than one that quietly disagrees with itself at the edges. Refusing a column request is far easier when the grain is written down and everybody signed it, which is most of the reason we insist on writing it down.
- Grain stated in plain language for every fact table before the table is built
- Additive, semi additive and non additive measures identified, so totals are not summed wrongly
- Requests that would change grain met by adding a table rather than amending the existing one
- Conformed dimensions shared across facts, so the same customer means the same thing everywhere
- Slowly changing dimension handling decided per attribute rather than applied uniformly