Fact table vs dimension table: разница
Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.
Короткий ответ
- Fact table (таблица фактов) — хранит события и измерения: что произошло, сколько, когда. Много строк.
- Dimension table (таблица измерений) — хранит контекст: кто, что, где. Мало строк.
- Они соединяются через FK: fact.dim_id = dim.id.
Классическая модель — star schema (звёздная схема): fact в центре, dimension вокруг.
Пример e-commerce
Fact table: orders
Хранит события заказов — что купили, сколько, когда.
order_id | user_id | product_id | store_id | date_id | qty | amount
---------|---------|------------|----------|---------|-----|-------
1001 | 42 | 850 | 7 | 21201 | 2 | 1200
1002 | 43 | 851 | 7 | 21201 | 1 | 500- Много строк (миллионы, миллиарды)
- Чаще всего integer / numeric колонки
- FK на dimension таблицы
Dimension table: users
Хранит характеристики пользователей.
id | name | email | signup_at | country
---|---------|------------------|------------|--------
42 | Alice | alice@example.com | 2024-05-01 | RU
43 | Bob | bob@example.com | 2025-02-15 | KZ- Меньше строк (тысячи / сотни тысяч)
- Описательные данные
Dimension table: products
id | name | category | price
----|----------------|------------|------
850 | iPhone 15 | Electronics| 80000
851 | AirPods Pro | Electronics| 20000Dimension table: date (date dim)
Стандарт — отдельная date dimension:
date_id | date | day | month | year | day_of_week | is_weekend
---------|------------|-----|-------|------|-------------|-----------
21201 | 2026-04-21 | 21 | 4 | 2026 | 2 (Tue) | falseУдобно для анализа по календарю (какой день недели, праздник, квартал).
Главные отличия
| Fact | Dimension | |
|---|---|---|
| Содержание | События, факты | Контекст, характеристики |
| Рост | Постоянно растёт | Медленно растёт |
| Строк | миллионы+ | тысячи-сотни тысяч |
| Типы колонок | Числа, FK | Текст, даты, категории |
| Grain (гранулярность) | событие / транзакция | объект (user, product) |
| FK наличие | много FK | обычно только PK |
| Обновления | append-only | редко |
Типы fact-таблиц
Transaction fact
Одна строка = одно событие. Стандарт.
Пример: один заказ = одна строка.
Snapshot fact
Фотография состояния на момент времени.
Пример: баланс счёта на конец каждого дня.
Accumulating snapshot
Разные стадии процесса (заказ оформлен, отгружен, доставлен) — одна строка, но с несколькими timestamp.
Типы dimension-таблиц
Slowly Changing Dimension (SCD)
Как обрабатывать изменения в dimension данных:
- SCD Type 1: обновление на месте (теряем историю)
- SCD Type 2: новая строка с valid_from / valid_to (сохраняем историю)
- SCD Type 3: отдельная колонка «prev_value» (частично сохраняем)
Пример SCD2 для users:
id | name | country | valid_from | valid_to | is_current
---|-------|---------|-------------|-------------|-----------
42 | Alice | RU | 2024-05-01 | 2025-08-01 | false
42 | Alice | KZ | 2025-08-01 | NULL | trueAlice переехала из RU в KZ.
Star schema vs snowflake schema
Star schema
Fact в центре, dimensions вокруг — все денормализованы.
dim_users
|
dim_date --- fact_orders --- dim_products
|
dim_stores- Плюсы: быстрые JOIN, простые запросы
- Минусы: дубликаты данных (denormalized)
Snowflake schema
Dimensions нормализованы (у dim есть свои suba-dim):
dim_products → dim_category → dim_department- Плюсы: меньше дубликатов
- Минусы: больше JOIN, сложнее
В DWH предпочитают star schema. Denormalization — не грех, а норма.
Проектирование
Шаг 1. Определить бизнес-процесс
«Заказы», «подписки», «клики».
Шаг 2. Определить grain
На каком уровне строка? Одна покупка? Один клик? Один день-пользователь?
Шаг 3. Определить dimensions
Кто, что, где, когда участвует? → dimension-таблицы.
Шаг 4. Определить facts
Что измеряем (количество, сумма, время)? → колонки в fact.
Шаг 5. Проверить
Можете ли ответить на ключевые бизнес-вопросы простыми SQL?
Пример запросов
Выручка по категориям за месяц
SELECT p.category, SUM(f.amount) AS revenue
FROM fact_orders f
JOIN dim_products p ON p.id = f.product_id
JOIN dim_date d ON d.date_id = f.date_id
WHERE d.year = 2026 AND d.month = 4
GROUP BY p.category;Fact хранит amount и ссылки. Dimension даёт контекст (category, month).
Топ-10 продуктов
SELECT p.name, SUM(f.qty) AS total_sold
FROM fact_orders f
JOIN dim_products p ON p.id = f.product_id
GROUP BY p.name
ORDER BY total_sold DESC
LIMIT 10;На собесе
Типичные вопросы:
«В чём разница fact и dimension?» Fact — события и измерения. Dimension — контекст.
«Star или snowflake?» В DWH — star. Denormalization оправдана скоростью запросов.
«Что такое SCD Type 2?» Сохранение истории изменений через valid_from/valid_to и is_current.
«Какая grain у fact table?» Уровень детализации. Один event = строка? Один день = строка?
Частые ошибки
Ошибка 1. Всё свалить в одну таблицу
Денормализованный «широкий» fact с 100 колонками — кошмар для чтения и записи.
Ошибка 2. Fact без FK
Если в fact хранить строки 'iPhone 15' вместо product_id — повторы, ошибки, сложнее обновить.
Ошибка 3. Dimension с мутирующими данными без SCD
Изменили category продукта → историческая аналитика сломалась.
Ошибка 4. Игнорировать date dimension
«У меня же date column в fact». Но нет контекста (is_weekend, holiday) → постоянно писать CASE.
Ошибка 5. Слишком мелкая grain
Fact на уровне «клик» на миллиардные данные — тяжело. Иногда лучше daily aggregate.
Связанные темы
FAQ
Fact всегда больше dimension?
Обычно да. Fact — события (много), dimension — сущности (меньше).
SCD1 или SCD2?
SCD2 если нужна история. SCD1 если достаточно текущего значения.
Star или snowflake schema?
Star для DWH практически всегда. Snowflake — академически «правильно», но сложнее.
Может быть fact без dimension?
Технически да, но редко полезно. Обычно есть date dim как минимум.
Тренируйте data modelling — откройте тренажёр с 1500+ вопросами для собесов.