Dimensional modeling по Кимбаллу: факты и измерения
Звезда vs снежинка, типы факт-таблиц, conformed/role-playing/junk-измерения, выбор грануляции и где ломаются новички.
Действуй как архитектор хранилища с 10+ лет на Кимбалле. Спроектируй dimensional-модель для процесса: {{business_process}}. Источники: {{source_systems}}. Платформа: {{warehouse}}.
Метод (4 шага Кимбалла)
1. Выбери бизнес-процесс
Не "продажи в целом", а конкретное событие: "оформление заказа", "отгрузка", "возврат". Один процесс — одна звезда. Не смешивай.
2. Объяви грануляцию (grain)
Самый важный шаг. Опиши одну строку факта одной фразой:
- "Одна позиция в заказе" — НЕ "один заказ"
- "Один транзакционный платёж" — НЕ "сумма за день"
Чем тоньше грануляция, тем больше вопросов можно ответить. Агрегаты потом — из неё, а не наоборот.
3. Определи измерения (dimensions)
Для каждого вопроса who/what/where/when/why/how → отдельное измерение. Типы:
- Conformed — общие между фактами (
dim_customerдля orders и returns). Идентичны, не "похожи". - Role-playing — одна таблица, несколько ролей (
dim_dateкак order_date, ship_date, due_date через views). - Junk — мусорные флаги в одной (
is_gift,shipping_method,payment_type) → одна junk-dim вместо 3 колонок в факте. - Degenerate — идентификатор без атрибутов (order_number) живёт в факте, не в dim.
- Mini-dimensions — быстро меняющиеся атрибуты выделяй (customer_segment может меняться еженедельно).
4. Определи факты (facts)
Три типа — выбирай осознанно: | Тип | Когда | Пример | | Transaction | Атомарные события | Один заказ-line | | Periodic snapshot | Состояние на конец периода | Баланс счёта на конец дня | | Accumulating snapshot | Процесс с фазами | Заказ от оформления до доставки (несколько дат) |
Факты содержат только: FK на dims + аддитивные меры. Текст, флаги — в измерения.
Звезда vs снежинка
- Звезда (плоские dims) — по умолчанию. Меньше джойнов, BI-инструменты любят, считается быстрее.
- Снежинка (нормализованные dims) — только если у dim есть огромные подгруппы с очень редким доступом или регуляторное требование.
Выход
## Grain
"Одна строка = ..."
## Bus matrix
| Процесс | dim_date | dim_customer | dim_product | dim_store |
| orders | X | X | X | X |
## Star: fact_orders
| Колонка | Тип | FK к | Аддитивность |
| order_date_key | INT | dim_date | - |
| customer_key | INT | dim_customer | - |
| quantity | DEC | - | additive |
| discount_pct | DEC | - | non-additive |
## Измерения
dim_customer: SCD-тип, ключ, атрибуты, источник
Anti-patterns
- ❌ Смешивать грануляции в одном факте ("сумма дня + одна позиция") — фильтры врут
- ❌ Класть текстовые атрибуты в факт ("status text") вместо junk-dim
- ❌ Использовать натуральный ключ источника как PK измерения — при ре-загрузке всё сломается; делай сурогатный
- ❌ "Один большой факт со всеми процессами" — теряешь грануляцию, JOIN-ы становятся арифметикой
- ❌ Снежинка by default — без причины ты добавляешь джойны, которые BI не оптимизирует
Slowly Changing Dimensions: Type 1/2/3/6 без боли
Когда что выбирать, что считается «изменением», как влияет на запросы и размер БД, и как мигрировать без переписывания витрин.
3NF vs star vs One Big Table: когда что выбирать
Trade-offs read perf / write complexity / storage для OLTP, OLAP и аналитики. Как мигрировать между моделями без переписывания клиентов.
Data contracts: producer ↔ consumer без сюрпризов
Schema versioning, политика breaking changes, валидация в pipeline, choice block vs warn, Avro/Protobuf/JSON Schema на практике.