Choose a dataset mode
A decision flow for picking cube, lattice, hybrid, or rows per dataset, plus how to tell when the server picked one you did not expect.
Each dataset in a dashboard picks one of four materializations independently. The choice is mechanical once you know two things about the dataset: whether any measure is non-additive, and how its filters work.
This page is the decision flow. For what each mode actually is and why the positioning runs the way it does, see Datasets and the four modes.
The flow
Answer in order. The first rule that fires is your answer.
1. Is every measure additive?
Additive means summing partial totals gives the right answer. sum, count,
min, and max are additive.
Non-additive means it is not. Any of these makes the dataset non-additive:
count(distinct ...)avgmedianpercentile_contor any percentilestddevvariancemode()
If every measure is additive, use cube. Stop here.
2. Is every dimension low-cardinality?
That means every field the dashboard filters, charts, or tabulates on has a small bounded set of values, and dates are bucketed rather than raw timestamps.
If not, use rows. Skip to step 4.
3. Are all the filters single-select?
A single-select filter fixes one value at a time.
If yes, use lattice. Stop here.
If a multi-select or range filter has to stay exact on a non-composable
measure, use hybrid. Non-composable means a distinct count, a true average, a
median, a percentile, a standard deviation, a variance, or a mode. A sum, count,
min, max, or a ratio of them composes across selected values without help, so
those do not force hybrid.
4. If you landed on rows, decide where the bytes go
A rows dataset on a warehouse connection can declare Parquet offload, which
moves its rows out of the shared inline budget so it can grow between publishes.
Three conditions, and each is a hard publish error rather than a surprise:
- Only a
rowsdataset. Nevercube,lattice, orhybrid. - Only on a warehouse connection, never on
self. - At most two per dashboard.
SQL Server has no Parquet path, and no rows or hybrid mode at all. See
Connect SQL Server.
The short form
| If | Use |
|---|---|
| Every measure is additive | cube |
| Something is non-additive, all dimensions low-cardinality, all filters single-select | lattice |
| As above, but a multi-select or range filter must stay exact on a non-composable measure | hybrid |
| A dimension cannot be bounded, or you need row-level detail | rows |
Cost and power both run cube then lattice then hybrid then rows. Take the
first one that is correct, not the most capable one. The reasoning behind that
ordering is in
how the choice is actually made.
You do not have to declare it
Leave mode off and the server auto-selects cube or lattice from the
measures and dimensions. rows and hybrid ship row-level bytes, so they must
be declared explicitly.
The publish report's mode_choices says what each dataset resolved to and why,
for example:
main -> lattice: a distinct count over low-cardinality dimensions
Read it. A mode you did not expect is usually the server noticing a measure is not what you thought it was, which is worth knowing before it becomes a wrong number.
The rule is enforced, so a wrong choice is loud
A cube dataset whose SQL computes a non-additive aggregate is rejected at
publish, naming the construct. Why it refuses rather than warns is
explained here. A cube measure declared with a non-additive
aggregation is a schema error. Validation warns about the same SQL earlier, when
your AI passes the dataset's mode.
The enforcement reads the SQL text, so it has a blind spot
A ratio or a distinct count computed inside a CTE or a subquery, then selected as a plain column, reads as additive from the outside and passes every check.
That is why Verify your numbers is a required step and not a nicety. The check there is exactly what catches a mode chosen wrongly for this reason.
A lattice must stay bounded
A lattice precomputes one cell per filter state, so its size is roughly the product of each dimension's number of values plus one. Every dimension declares its bound: a list of values for a category, or buckets for a date.
If it grows past the inline cap, the fix is to drop or bound a dimension. A lattice can never offload to Parquet, so there is no way to buy your way out of an unbounded one. The arithmetic is in the lattice cell budget, and offloading to Parquet covers what Parquet does and does not buy.
Check it worked
mode_choicesin the publish report names the mode you intended for each dataset.- The publish was not refused for a non-additive aggregate in a
cube. - You ran Verify your numbers on each additive measure, and the two legs agreed. That is the step that confirms the mode was right, rather than merely accepted.