skip to content

What is an outrigger dimension, and when is attaching one to another dimension justified?

level: middleimportance: nice to knowfreq 24%

answer

  1. a dimension with a foreign key of its own
  2. a store's opening date needs the calendar
  3. use it sparingly, not routinely
  4. the alternative is to copy two columns in
  5. one is an exception, five is a normalized model

basics

~20 s

An outrigger is a dimension table referenced by a foreign key from another dimension table, such as a store dimension pointing at the shared date dimension for its opening date. It is a sanctioned, sparing exception to the flat star.

solid answer

~50 s

Normally a dimension is flat: a fact joins one dimension and everything it needs is there. An outrigger breaks that deliberately — a dimension carries a foreign key to a second, independently meaningful dimension. The canonical case is a date attribute inside a non-date dimension: `dim_store.first_open_date_key` pointing at the shared `dim_date` so you can group stores by opening fiscal quarter without re-implementing the calendar. Use it sparingly: when the referenced table is a genuinely shared standard dimension, when its attribute set is large enough that copying it in would be wasteful, and when the relationship is stable. Otherwise flatten — copy the two or three attributes you actually need (`first_open_year`, `first_open_month_name`) into the host dimension. The costs are an extra join, an attribute set that changes independently of the host row, and a model that drifts toward being normalized by accident.

code

sql · 15 lines
sql
CREATE TABLE dim_store (
  store_key           INTEGER PRIMARY KEY,
  store_name          VARCHAR(80) NOT NULL,
  region              VARCHAR(40) NOT NULL,
  first_open_date_key INTEGER NOT NULL  -- outrigger to dim_date
);

SELECT od.fiscal_quarter AS opening_fiscal_quarter,
       SUM(f.extended_amount) AS revenue
FROM   fact_sales f
JOIN   dim_store s  ON s.store_key = f.store_key
JOIN   dim_date  od ON od.date_key = s.first_open_date_key
JOIN   dim_date  td ON td.date_key = f.date_key
WHERE  td.calendar_year = 2026
GROUP BY od.fiscal_quarter;

go deeper

for a junior

Recognize the shape: a dimension table holding a foreign key to another dimension table, such as a store row pointing at the shared date dimension for its opening date.

for a middle

Explain the trade-off you are making — one extra join in exchange for reusing a whole shared vocabulary — and be able to argue for flattening two attributes instead when that is all anyone needs.

for a senior

Show the operational awareness: aliasing when the fact also joins the same dimension directly, host and outrigger rows changing on independent schedules, and catching accumulation before the star quietly normalizes.

for a principal

Own the guardrail: a documented policy on which shared dimensions may be outriggers, review pressure against routine use, and a standard for flattening common attributes into host dimensions instead.

## The default and the exception A dimensional model's default is flat dimensions: the fact table joins a dimension, and every attribute an analyst needs is a column on that one row. That flatness is the whole ergonomic argument for the design — one join, no hierarchy to navigate, obvious column names. An outrigger is the sanctioned exception. It is a dimension table that itself holds a foreign key to another dimension table: ```sql CREATE TABLE dim_store ( store_key INTEGER PRIMARY KEY, store_name VARCHAR(80) NOT NULL, store_type VARCHAR(30) NOT NULL, region VARCHAR(40) NOT NULL, first_open_date_key INTEGER NOT NULL -- outrigger to dim_date ); ``` Now `dim_store` can be joined to `dim_date` to answer "revenue by store opening fiscal quarter", reusing the full calendar — fiscal periods, holiday flags, day-of-week — without copying dozens of columns into every store row or re-deriving fiscal logic in a report. ## When it earns its place Three conditions, and it is worth being able to state them: 1. **The referenced table is a genuinely shared, standard dimension.** Date is the archetype; a currency or a geography dimension can qualify. The value comes from reusing one definition that other parts of the model already trust. 2. **The attribute set is large enough that copying it in would be wasteful or inconsistent.** A calendar has dozens of attributes; flattening all of them into a host dimension for one date is silly, and flattening a few of them invites someone to derive the missing one badly. 3. **The relationship is stable and single-valued.** One store has one opening date. If the relationship were multi-valued you would need a different construct entirely. A second use is attaching an existing demographic or profile dimension to a host dimension so that the host can expose a current profile without inlining its columns. ## When to flatten instead Most of the time, flatten. If reports only ever want the opening year and month name, put `first_open_year` and `first_open_month_name` directly on `dim_store`. Two extra columns on a small dimension cost nothing, remove a join, and remove a question from every analyst who meets the model. The rule of thumb is: outrigger when you need the referenced dimension's whole vocabulary, flatten when you need two attributes from it. ## The costs to name - **An extra join.** Small in itself, but each one is a step the analyst must know to take, and the ergonomic argument for the flat star is exactly that they should not have to. - **Ambiguity when the outrigger is also joined directly.** If the fact already joins `dim_date` as the transaction date and the store outrigger reaches `dim_date` as the opening date, a query touching both must alias carefully or it will produce a confusing result. Role naming discipline applies here too. - **Independent change.** The host dimension row and the outrigger row version on different schedules, so a query reading them together may mix a historical host attribute with a current outrigger attribute unless you are deliberate about it. - **Drift.** One outrigger is a documented exception; five outriggers is a normalized dimension nobody agreed to build, and the model quietly loses the property that made it easy to query. ## How it differs from neighbouring ideas An outrigger is a reference from one dimension to another *independently meaningful* dimension. It is not a bridge table — bridges resolve multi-valued relationships. It is not a mini-dimension, which is a volatility split whose key normally lands on the fact table. And it is distinct from snowflaking a hierarchy out of a dimension for normalization's sake: the outrigger points at a table that exists in its own right and is used elsewhere, whereas a snowflaked hierarchy level exists only as a decomposed piece of its parent dimension. ## What an interviewer is checking That you know the term, that you can give the date-inside-a-non-date-dimension example, and — most of all — that your instinct is "sparingly". A candidate who reaches for outriggers routinely is rebuilding a normalized schema inside a dimensional model without noticing; a candidate who has never heard the word but says "I'd just copy the opening year onto the store row" has the right instinct with the wrong vocabulary. The good answer has both.

  • When would you flatten the attributes into the host dimension instead of using an outrigger?
    When reports need only two or three attributes from the referenced dimension. Copying `first_open_year` and `first_open_month_name` onto the store row costs two small columns, removes a join, and removes a question from every analyst. Reserve the outrigger for when you genuinely need the referenced dimension's whole vocabulary.
  • What goes wrong if a model accumulates many outriggers?
    You end up with a normalized dimension nobody agreed to build: analysts must traverse several joins to describe one fact row, the flat-star ergonomics disappear, and each hop is a place to get the join wrong. One documented exception is fine; a habit of it is a design drift worth catching in review.

saying these in an interview costs you the question

  • Uses outriggers routinely instead of flattening two attributes
  • Confuses an outrigger with a multi-valued bridge table
  • Forgets to alias when the fact also joins the same dimension
  • Thinks an outrigger is required whenever a dimension holds a date
  • Treats it as forbidden rather than a sparing exception

context