Две библии Data Warehousing
В 1990-2000-е годы вокруг DWH сформировались две школы. Две методологии, две книги, два классика:
- Bill Inmon — “Building the Data Warehouse” (1992). Подход: централизованный, нормализованный, top-down.
- Ralph Kimball — “The Data Warehouse Toolkit” (1996). Подход: децентрализованный, денормализованный, bottom-up, dimensional.
Эти два подхода десятилетиями конкурировали в академии и индустрии. Оба до сих пор применяются. Современный data engineering часто использует смесь обоих — но знать различия критично для понимания, почему DWH устроен так, как устроен.
В этом уроке разберём оба, потом покажем на одном примере (заказы e-commerce) как одни и те же данные моделируются по-разному.
Inmon: Corporate Information Factory
Идея
Inmon мыслит DWH как фабрику корпоративной информации. Центральная идея: построить единое нормализованное хранилище всех данных компании (Enterprise Data Warehouse, EDW), а из него — подмножества (data marts) для конкретных доменов.
Архитектура:
[Sources] -> [Staging] -> [EDW (3NF)] -> [Data Marts (dimensional)] -> [BI]
EDW содержит данные в 3NF нормализованной форме — как в OLTP-базах, без дубликации, с foreign keys. Это single source of truth. Из EDW строятся mart-ы — уже денормализованные, оптимизированные под конкретные отделы (sales mart, marketing mart, finance mart).
Почему 3NF в EDW
Аргумент Inmon-а: компания меняется. Появляются новые бизнес-вопросы, новые BI-инструменты, новые ML-кейсы. Если данные хранятся в денормализованной форме (заточенной под старые отчёты) — пересборка под новые нужды дорогая. Нормализованная форма универсальна: из неё можно построить любую денормализацию.
Плюсы Inmon
- Единый источник истины. Все данные в одном месте, в одной форме. Нет противоречий между mart-ами.
- Гибкость для новых use cases. Из нормализованной формы можно построить любую денормализацию.
- Чистота данных. Унификация на уровне EDW — данные приходят к marts уже clean.
- Историчность. Нормализованная схема легко расширяется SCD (slowly changing dimensions) для отслеживания изменений.
Минусы Inmon
- Дорого строить. EDW — это огромная инвестиция перед получением первого ROI. Месяцы-годы работы.
- Marts всё равно нужны. Аналитики работают с marts (быстрые JOIN-ы), EDW — это инфраструктура. Двойной слой.
- Long time-to-value. Бизнес ждёт месяцы первого отчёта.
- Сложность обслуживания. Большая 3NF схема, много foreign keys, много таблиц.
Kimball: Dimensional Modeling и Data Bus
Идея
Kimball мыслит DWH как набор соединяемых data marts. Не центральное хранилище, из которого выводятся marts — а сразу marts с общими (conformed) dimensions. Marts соединяются через Data Bus — архитектурный паттерн, где shared dimensions (dim_customer, dim_date, dim_product) используются всеми domains.
Архитектура:
[Sources] -> [Staging] -> [Multiple Data Marts (dimensional)] -> [BI]
|- sales mart
|- marketing mart
|- finance mart
[shared conformed dimensions]
Внутри mart-а — dimensional model: star schema (один fact + dimensions) или snowflake (нормализованные dimensions). Это разбирается в модуле 8 детально.
Conformed dimensions
Ключевая идея Kimball — conformed dimensions. Это shared таблицы, используемые всеми mart-ами. Например, dim_customer — одна таблица, в которой customer определяется одинаково для sales mart и marketing mart. Это гарантирует консистентность: “продажи клиенту X” и “marketing campaigns для клиента X” — про одного человека.
Плюсы Kimball
- Быстрый time-to-value. Первый mart можно построить за недели, не месяцы.
- Простота для аналитиков. Star schema — это два-три JOIN, легко читается, легко SQL.
- Производительность. Денормализованные dimensions + fact = быстрые JOIN-ы.
- Итеративная разработка. Mart за mart-ом, каждый приносит value.
- Естественно для BI tools. Tableau, Looker, Power BI — все оптимизированы под dimensional model.
Минусы Kimball
- Возможны inconsistencies. Если conformed dimensions не строго управляются — разные marts получают разные определения.
- Денормализация = дублирование. Customer info лежит в каждом mart-е, обновления нужно повторять.
- Не все use cases подходят. Сложная аналитика с many-to-many связями плохо ложится в star.
- Сложнее historical refactoring. Если меняется структура mart-а — нужно переписать.
Сравнение по 5 параметрам
Две школы, два подхода к проектированию
| Аспект | Inmon | Kimball |
|---|---|---|
| Архитектура | EDW + marts | Marts с conformed dimensions |
| Storage в EDW | Нормализованная 3NF | Денормализованная (star) |
| Time-to-value | Месяцы | Недели |
| Подход | Top-down | Bottom-up |
| Лучшие use case | Большие enterprise, regulated industries | Маркетинг, sales, продуктовая аналитика |
| Скорость queries | Медленнее (нужны JOIN-ы) | Быстрее (star JOIN-ы) |
| Гибкость к изменениям | Высокая (3NF универсальна) | Средняя (нужен refactor mart) |
| Сложность ETL | Высокая (две стадии) | Средняя (одна стадия в mart) |
| BI tools fit | Через marts | Прямой fit |
Пример: e-commerce заказы в обоих стилях
Возьмём типичную задачу: интернет-магазин хочет анализировать продажи.
Источники: Postgres (заказы, клиенты, продукты), Stripe (платежи), маркетинговый CRM (campaigns).
Inmon стиль (3NF EDW)
EDW содержит нормализованные таблицы — почти зеркало OLTP, но с историей:
CREATE TABLE edw.customers (
customer_id BIGINT PRIMARY KEY,
email TEXT,
name TEXT,
signup_date DATE,
country TEXT,
-- ... 30 атрибутов
valid_from DATE, -- для SCD Type 2
valid_to DATE, -- NULL если current
is_current BOOLEAN
);
CREATE TABLE edw.products (
product_id BIGINT PRIMARY KEY,
sku TEXT,
name TEXT,
category_id BIGINT REFERENCES edw.categories(category_id),
-- ...
);
CREATE TABLE edw.categories (
category_id BIGINT PRIMARY KEY,
name TEXT,
parent_category_id BIGINT -- иерархия
);
CREATE TABLE edw.orders (
order_id BIGINT PRIMARY KEY,
customer_id BIGINT REFERENCES edw.customers,
order_date DATE,
status TEXT,
-- ...
);
CREATE TABLE edw.order_items (
order_id BIGINT REFERENCES edw.orders,
product_id BIGINT REFERENCES edw.products,
qty INT,
unit_price NUMERIC,
PRIMARY KEY (order_id, product_id)
);
CREATE TABLE edw.payments (
payment_id BIGINT PRIMARY KEY,
order_id BIGINT REFERENCES edw.orders,
amount NUMERIC,
-- ...
);
Все таблицы нормализованы, foreign keys, без дубликации. SCD Type 2 на dimensions для истории.
Запрос аналитика “продажи по странам и категориям”:
SELECT
c.country,
cat.name AS category,
SUM(oi.qty * oi.unit_price) AS revenue
FROM edw.orders o
JOIN edw.customers c ON o.customer_id = c.customer_id
JOIN edw.order_items oi ON o.order_id = oi.order_id
JOIN edw.products p ON oi.product_id = p.product_id
JOIN edw.categories cat ON p.category_id = cat.category_id
WHERE o.order_date >= '2026-01-01'
GROUP BY 1, 2
ORDER BY 3 DESC;
5 JOIN-ов. На правильно проиндексированном Snowflake/BigQuery работает, но медленнее, чем dimensional model.
Kimball стиль (Star schema mart)
Для sales mart строится dimensional model — один fact + несколько dimensions:
-- Fact: orders с метриками
CREATE TABLE mart.fact_order_items (
order_item_id BIGINT,
order_id BIGINT,
date_key INT, -- FK to dim_date
customer_key BIGINT, -- FK to dim_customer
product_key BIGINT, -- FK to dim_product
qty INT,
unit_price NUMERIC,
total_amount NUMERIC, -- precomputed
-- ...
);
-- Conformed dimension: customer (используется и в marketing mart)
CREATE TABLE mart.dim_customer (
customer_key BIGINT, -- surrogate key
customer_id BIGINT, -- natural key из OLTP
email TEXT,
name TEXT,
country TEXT,
signup_date DATE,
signup_year INT, -- precomputed для удобства
signup_month INT,
-- ...
valid_from DATE,
valid_to DATE,
is_current BOOLEAN
);
-- Dimension: product (денормализована, category info inline)
CREATE TABLE mart.dim_product (
product_key BIGINT,
product_id BIGINT,
sku TEXT,
name TEXT,
category_name TEXT, -- !!! денормализовано
category_parent_name TEXT, -- !!! иерархия inline
brand TEXT,
-- ...
);
-- Dimension: date
CREATE TABLE mart.dim_date (
date_key INT, -- 20260517
full_date DATE,
year INT,
quarter INT,
month INT,
month_name TEXT,
day_of_week INT,
is_weekend BOOLEAN,
-- ...
);
Тот же запрос:
SELECT
c.country,
p.category_name,
SUM(f.total_amount) AS revenue
FROM mart.fact_order_items f
JOIN mart.dim_customer c ON f.customer_key = c.customer_key
JOIN mart.dim_product p ON f.product_key = p.product_key
JOIN mart.dim_date d ON f.date_key = d.date_key
WHERE d.year = 2026
GROUP BY 1, 2
ORDER BY 3 DESC;
3 JOIN-а вместо 5. Денормализованные dimensions — нет иерархического JOIN-а по categories. Precomputed total_amount — нет вычисления на лету. На современном Snowflake/BigQuery — в 2-3 раза быстрее, чем Inmon-стиль, и проще для аналитика.
Inmon: 3NF из 7 таблиц с foreign keys. Kimball: 1 fact + 3 conformed dimensions
customers, orders, items,
products, categories,
payments… (~10 таблиц)Inmon EDW: 7+ нормализованных таблиц, foreign keys, JOIN-цепочки. Запрос требует 5+ JOIN-ов. Гибче к изменениям
fact_orders +
dim_customer + dim_product +
dim_date (~4 таблицы)Kimball mart: 1 fact (заказы) + 3 dimensions (customer, product, date). Денормализация уменьшает JOIN-ы. Быстрее, проще для аналитика
Современный гибрид: dbt + Snowflake
Реальность 2026 года: чистого Inmon или чистого Kimball больше нет. Стандартная архитектура — гибрид:
- Raw layer: сырые данные из источников (как есть, JSON или dump).
- Staging layer: очищенные таблицы, близкие к OLTP (нормализованные, как Inmon). Создаётся в dbt.
- Intermediate layer: business logic, объединения, computed fields.
- Mart layer: dimensional models (как Kimball). Star schemas для каждого домена.
- Presentation layer: aggregated tables для конкретных BI-нужд.
Каждый слой — это set of dbt models. Snowflake/BigQuery держит всё.
В чём гибрид: staging — это Inmon-стиль (clean normalized), marts — это Kimball-стиль (dimensional). Получаем плюсы обоих: гибкость + быстрый BI.
# dbt project структура
models/
staging/ # Inmon-style normalized
stg_orders.sql
stg_customers.sql
stg_products.sql
intermediate/ # business logic
int_orders_with_items.sql
marts/ # Kimball-style dimensional
sales/
dim_customer.sql
dim_product.sql
dim_date.sql
fact_orders.sql
marketing/
...
Когда что выбирать
Чистый Inmon — почти не встречается в 2026. Может быть оправдан в банках с долгой историей и регуляторными требованиями.
Чистый Kimball — рабочий вариант для маленьких компаний, у которых один-два бизнес-домена. Маркетинг-аналитика — типичный пример.
Гибрид (90% случаев) — реальная архитектура в Modern Data Stack. Staging нормализованный, marts dimensional. Это что обучают bootcamps и используют startups.
Углубление в dimensional modeling — модуль 8. Углубление в dbt и transformations — модуль 13.
data-modeling: Inmon Corporate Information Factory — глубокое погружение data-modeling: Kimball dimensional model — полный разбор методологии dbt: слои staging/intermediate/marts — как реализуется гибридДля junior data engineer: не зацикливайся на споре Inmon vs Kimball — это академический. Учись dimensional modeling (модуль 8), это база. И учись dbt — это инструмент, который оба подхода реализует.
Попробуй сам
- Возьми любой публичный dataset (например, Northwind). Спроектируй его в обоих стилях: Inmon (3NF) и Kimball (star schema). Сравни количество таблиц, количество JOIN-ов для типичных queries.
- Прочитай первую главу обеих книг (Inmon и Kimball) на Google Books preview. Заметь, как они аргументируют свой подход.
- Найди в реальном dbt project (open-source на GitHub: dbt-jaffle-shop, dbt-mta-shapes) структуру models/. Увидишь staging + marts — типичный гибрид.
- Спроектируй гипотетический mart для twitter analytics: tweets, users, hashtags. Какие fact и dimensions?