Спроси любого уважаемого аналитика или инженера данных о том, какие бывают способы моделирования данных, тебе ответят: звезда, 3NF и DataVault. Спроси ИИ, получишь примерно такой же ответ. Придешь на какой-нибудь проект в компанию, также скорее всего встретишь там кого-нибудь из этих друзей. В 90% материалах про методологии моделирования освещаются только эти трое. Как будто других методологий не существует.

Да, эта троица, наверное, самая популярная и подходящая под большую часть задач, но в мире есть еще уйма других не менее интересных способов как организовать свои данные. И сегодня мы постараемся целиком их рассмотреть. Если какие-то упустил, пишите в комментах, интересно будет почитать.

Сперва начнем с уже упомянутой троицы, раз про них заговорили и которых нельзя не упомянуть, раз статья называется «полный гайд». А далее пойдут все менее популярные и даже редкие методологии.

3NF или Третья нормальная форма

Предложенная Эдгаром Коддом в 1971 году и взятая за основу архитектуры хранилища данных Биллом Инмоном, третья нормальная форма широко применялась и до сих пор применяется во многих системах. Что она собой представляет?

Ее главная задача – избежать избыточности данных. Для этого данные нормализуются (то есть разбиваются) на несколько связанных сущностей (таблиц). Это похоже на объектно-ориентированный подход в программировании: мы разбиваем данные на связанные сущности/объекты (клиент, заказ, товар, транзакция).

Очень важное правило в 3NF – каждый неключевой атрибут такой сущности/таблицы (ФИО, дата заказа, категория товара) должен зависеть от ключевого атрибута (ID клиента, номер заказа, ключ товара соответственно). Сущность/таблица может ссылаться на другую таблицу через внешние ключи (FK).

Пример запроса:

SELECT
o.order_id,
c.customer_name,
p.product_name,
oi.quantity,
p.price,
oi.quantity * p.price AS total_price
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id
ORDER BY o.order_id;

Плюсы

  • Высокая целостность данных

  • Минимизация избыточности данных

  • Легко разрабатывать (все интуитивно понятно)

Минусы

  • Потребуется использование много join-ов

  • Сложно поддерживать и очень легко сломать (пример: была связь один-к-одному, стала многие-ко-многим и таблицу и ETL нужно полностью переписывать).

Когда применяется?

Чаще всего третья нормальная форма применяется в транзакционных система (OLTP), а проще говоря, в операционных или учетных система типа CRM, ERP и другое.

Иногда также применяется и в аналитических хранилищах данных. Как я ранее подсвечивал, главным идеологом применения ее в DWH был Инмон, где центральный слой хранилища данных выстроен в 3NF. Такой слой сейчас принято называть DDS (в России) или Silver (за бугром).

Звезда и снежинка

Предложенная в 90-ых Ральфом Кимбаллом данный подход используется до сих пор и используется повсеместно. Наверное, самая популярный способ моделирования в DWH, потому что универсальный и подходит как маленьким, так и большим проектам.

В центре таблица фактов с показателями: сумма заказа, количество товаров. Вокруг —измерения, которые хранят «описание» этих показателей: когда совершены заказы, какие заказаны товары, какие клиенты купили.  

Основная разницу между звездой и снежинкой в том, что в звезде измерения «денормализованы» - измерения не связаны между собой, а в снежинке связаны, то есть «нормализованы» (пример: измерение продуктов связано с измерением категории продуктов).

Пример запроса:

SELECT 
p.product_name, 
d.year, 
SUM(f.sales_amount) AS total_revenue
FROM fact_sales f
JOIN dim_product p ON f.product_id = p.product_id
JOIN dim_date d ON f.date_id = d.date_id
GROUP BY p.product_name, d.year
ORDER BY total_revenue DESC;

Плюсы

  • Простота для пользователей

  • Может быстро работать на больших объемах

Минусы

  • Сложно поддерживать (как и 3NF)

  • Высокий риск несогласованности между измерением и фактом

Когда применяется?

В аналитических хранилищах данных. Особенно на малых или средних проектах, где не так много данных и (главное!) источников данных.

DataVault

Замыкает нашу «большую тройку» методология Data Vault, которая ассоциируется с двумя своими основными достоинствами: гибкостью и масштабируемостью.

Созданный Дэном Линстедтом в 2000 году, этот подход стал ответом на хаос микросервисной архитектуры и потребность в экстремальной гибкости. Если 3NF стремится к порядку, а Звезда к скорости, то Data Vault стремится к тому, чтобы никогда не переделывать уже созданное при добавлении новых источников. Другими словами, чтобы в первую очередь было максимально удобно поддерживать модель данных, а уже потом пользоваться ею.

В основе лежат три типа сущностей:

  • Хабы (Hubs) — это «существительные», хранящие только уникальные бизнес-ключи (например, ID клиента), которые никогда не меняются

  • Линки (Links) — это «глаголы», описывающие связи между Хабами (например, факт покупки товара клиентом)

  • Сателлиты (Satellites) — это «прилагательные», содержащие все описательные атрибуты и полную историю их изменений во времени

Аналитикам этим всем пользоваться достаточно сложно. Внизу пример стандартного запроса. Но слышал где-то хорошую мысль, что DataVault не про использование данных, а про их хранение.

SELECT 
    h_c.customer_bk AS customer_id, 
    s_c.last_name, 
    s_o.amount
FROM hub_customer h_c
JOIN sat_customer_details s_c ON h_c.customer_pk = s_c.customer_pk
JOIN link_order l_o ON h_c.customer_pk = l_o.customer_pk
JOIN hub_order h_o ON l_o.order_pk = h_o.order_pk
JOIN sat_order_finance s_o ON h_o.order_pk = s_o.order_pk
WHERE s_c.is_current = true;

Этот запрос показывает главную особенность: даже для простого отчета нужно соединить минимум 5 таблиц.

Плюсы

  • Масштабируемость: можно добавлять новые системы-источники, просто пристраивая новые модули, не ломая старые процессы

  • Параллельная загрузка: Хабы не зависят друг от друга, поэтому данные можно заливать в систему максимально быстро

  • Легко реализовать версионность без избыточности данных

Минусы

  • Сложность для аналитиков из-за огромного количества таблиц, сложно писать SQL-запросы

  • Нагрузка на базу данных выше, так как много join, не каждая база выдержит

  • Для разработки ETL потребуется инструмент автоматизации, потому что вручную разрабатывать пайплайны для такого количества табл��ц – самоубийство

Когда применяется?

В крупных, быстро развивающихся аналитических хранилищах данных с десятками или сотнями источников данных, где бизнес-модель меняется очень часто. DataVault идеально подходит для детального слоя (DDS или Silver), поверх которого всё равно приходится строить упрощенные витрины или «звезды» для аналитиков.

P.S. Поговаривают, что Дэн Линстедт изобрел эту методологию специально для АНБ.

Anchor modeling

Если DataVault вам казался избыточным в части нормализации, то anchor modeling в этом случае чемпион нормализации, который возводит ее в абсолют. Некий Ларс Рённбэк предположил: «А почему бы нам не строить хранилища в 6 нормальной форме?». И претворил безумную идею в жизнь.

Что такое 6NF простыми словами? Если в DataVault атрибуты сущностей делились на группы (сателлиты), то в 6NF у каждого атрибута своя таблица!

Архитектура состоит из четырёх элементов:

  • Якоря (Anchors): Сущности (например, «Клиент»), которые содержат только суррогатный ключ и технические метаданные.

  • Атрибуты (Attributes): Каждое свойство (фамилия, адрес, телефон) хранится в отдельной таблице, привязанной к якорю.

  • Связи (Ties): Отдельные таблицы для отношений между якорями.

  • Узлы (Knots): Общие свойства или справочники с редкими изменениями (например, пол или статус)

Пример: Чтобы собрать данные о клиенте, которые в классической таблице занимали бы одну строку, здесь нужно соединить якорь со всеми его атрибутами.

SELECT 
    a.AC_ID, 
    an.AC_Name, 
    ae.AC_Email, 
    ap.AC_Phone
FROM Anchor_Customer a
LEFT JOIN Attribute_Customer_Name an ON a.AC_ID = an.AC_ID
LEFT JOIN Attribute_Customer_Email ae ON a.AC_ID = ae.AC_ID
LEFT JOIN Attribute_Customer_Phone ap ON a.AC_ID = ap.AC_ID;

Этот запрос наглядно показывает «цену» метода: количество JOIN-ов растет пропорционально количеству нужных полей.

Плюсы

  • Гибкость, гибкость, гибкость! Новые атрибуты добавляются как новые таблицы, что исключает риск сломать существующие процессы или отчеты.

  • Очень сильно экономится место

  • Элементарно просто реализовать и поддерживать историчность, ведь она фиксируется для каждого атрибута отдельно.

Минусы

  • Очень высокая нагрузка на БД из-за огромного количества join-ов.

  • Понять структуру из сотен и тысяч таблиц без специализированного инструмента визуализации или генератора запросов практически невозможно.

  • Без какого-либо инструмента автоматизации разрабатывать ETL невозможно.

Когда применяется?

В очень крупных проектах аналитических хранилищ, где большое количество источников, очень частые изменения и невероятно много инженеров.

One big table или wide tables

От чемпиона «нормализации» переходим к чемпиону «денормализации». Из названия понятно – делаем одну или несколько гигантских таблиц/витрин, и в этом будет заключаться вся наша модель данных. Зачем нам плодить кучу таблиц, сложно разрабатывать для них ETL, а потом сложно ими пользоваться, когда все данные можно впихнуть в одну таблицу и горя не знать. Особенно, когда ни одного join-а.

Все запросы пишем над одной витриной:

SELECT
product_category,
order_year,
SUM(order_amount) AS total_revenue
FROM sales_obt
GROUP BY product_category, order_year
ORDER BY total_revenue DESC;

Плюсы

  • Бешеная производительность из-за отсутствия JOIN-ов.

  • Идеально для ИИ и LLM, ведь Языковым моделям гораздо проще писать запросы к одной таблице (SELECT ... WHERE), чем пытаться разобраться в хитросплетениях связей и не «галлюцинировать» на джойнах.

Минусы

  • Колоссальная избыточность, так как если у клиента сменится фамилия, в классическом OBT вам придется обновить миллионы строк с его транзакциями, вместо одной строки в справочнике. Или принять, что старые данные будут необновленными.

  • Практически невозможно поддерживать, потому что вся ваша модель один большой кусок … монолита

  • Высокая стоимость хранения, потому что данные дублируются

Когда применяется?

В аналитике для анализа долгосрочных трендов и кликстрима. Также OBT становится стандартом при подготовке данных для AI-агентов, которым нужна максимально простая и «плоская» структура для работы без ошибок.

Activity schema

Следующая методология весьма похожа на предыдущую. Есть основная таблица, не обязательно широкая. Она хранит в себе события или действия пользователей, или систем, или объектов. Каждая строка – какой-то действие. К примеру, действия пользователей на маркетплейсе. У каждого действия есть привязка к объекту, который его совершает и времени.

user_id

event_type

event_time

product_id

device_type

101

login

2026-03-01 10:00

NULL

mobile

101

view_product

2026-03-01 10:02

845

mobile

101

add_to_cart

2026-03-01 10:05

845

mobile

101

purchase

2026-03-01 10:07

845

mobile

204

search

2026-03-01 10:10

NULL

desktop

204

view_product

2026-03-01 10:11

233

desktop

204

add_to_favorites

2026-03-01 10:12

233

desktop

Часто применяется в аналитических хранилищах для задач расчет конверсии, кликстрима или чего-то другого.

Пример задачи – сколько людей зашли на сайт и совершили покупку до того, как зашли снова?

WITH logins AS (
SELECT
user_id,
event_time AS login_time,
LEAD(event_time) OVER (
PARTITION BY user_id
ORDER BY event_time
) AS next_login_time
FROM user_activity
WHERE event_type = 'login'
)

SELECT COUNT(DISTINCT l.user_id)
FROM logins l
JOIN user_activity a
ON a.user_id = l.user_id
AND a.event_type = 'purchase'
AND a.event_time > l.login_time
AND (a.event_time < l.next_login_time OR l.next_login_time IS NULL);

Плюсы

  • Очень простой ETL, потому что создание новых «кубиков» данных занимает в среднем 15–20 минут

  • Переиспользование логики: алгоритмы (например, для LTV), написанные для одной компании, могут быть без изменений запущены в другой, если обе используют этот стандарт.

  • Скорость работы, потому что отсутствуют join-ы

Минусы

  • Очень сложно писать SQL, потребуется много использовать оконных функций

  • Может не хватать описательных атрибутов, которые придется join-ить

Когда применяется?

В задачах, где основной фокус направлен на Customer Journey (путь клиента), маркетинговую атрибуцию и анализ продуктовых метрик. Это отличный выбор для стартапов и компаний, которые хотят быстро получать ответы на сложные вопросы («как долго клиент идет от первого визита до лида?»), не тратя месяцы на проектирование классического DWH.

Подход не применим в тех задачах, где нет анализы с привязкой ко времени.

EAV

Тоже весьма гибкий подход, который из вашей таблицы в 1 млн. строк сделает таблицу с 100 млн. Так происходит, потому что атрибуты сущностей хранятся не в отдельных столбцах, как мы привыкли или в отдельных таблицах (как в anchor modeling), а в следующем виде: сущность – атрибут – значение. Представьте интернет-магазин электроники: у пылесоса важна мощность всасывания, у смартфона — объем оперативной памяти, а у флешки — тип разъема.

Вот так выглядит сама таблица

entity_id

attribute

value

101

height

180

101

weight

75

101

blood_type

O

102

height

165

102

weight

60

 

Здесь entity_id — это сущность (например, человек), attribute — название свойства, а value — его значение. Таким образом, вместо колонок height, weight, blood_type все атрибуты хранятся в строках одной таблицы.

Весьма гибкий подход, особенно когда часто нужно добавлять новые свойства объектов, но при этом сильно усложняются SQL-запросы.

SELECT h.entity_id
FROM entity_attributes h
JOIN entity_attributes w
ON h.entity_id = w.entity_id
WHERE h.attribute = 'height'
AND w.attribute = 'weight'
AND h.value::int > 170
AND w.value::int < 80;

Как видно, приходится постоянно join-ить одну и ту же таблицу, чтобы вытащить в одну строку несколько атрибутов одного объекта. И конечно, при таком подходе таблицы разрастаются по количеству строк. И выходит, что мы постоянно join-им одну и ту же таблицу, которая еще содержит миллионы строк. К этому еще прибавляем то, что значения разных атрибутов, которые могут быть разных типов (дата рождения и адрес регистрации) хранятся в одном столбце, что тоже весьма не оптимально. Правда стоит упомянуть, что можно разделить разные типы на разные столбцы (value_str, value_date, value_int) или даже на разные таблицы.

Плюсы

  • Вы можете добавить сотни новых характеристик товаров хоть каждый час, и вам не нужно менять схему базы данных

  • Легко реализовать историчность

  • Отсутствие избыточности, когда данные дублируются из-за историчности

Минусы

  • Очень низкая производительность

  • Сложность запросов

  • Проблемы с типизацией (правда, которые всякими костылями можно решить, как говорилось выше)

Когда применяется?

В системах с разреженными данными и постоянно меняющимися требованиями. Классические примеры — управление каталогами товаров в E-commerce, медицинские информационные системы, где у каждого пациента свой уникальный набор анализов, или CRM-системы, где пользователи сами создают кастомные поля для контактов. EAV часто сосуществует с реляционной моделью: базовые поля (ID, SKU, номер заказа) лежат в обычных таблицах, а всё переменное — в EAV-слое. В аналитических хранилищах, когда требуется обрабатывать большие объемы данных, такое лучше не применять.

Документориентированная

Раз уж мы заговорили про системы, в которых постоянно меняются требования, то поговорим про неструктурированные данные. То есть такие данные, которые не имеют какую-то определенную структуру и для разных экземпляров объектов (к примеру, для разных товаров) могут быть разных форматов.

Подсвечу, что слово «документориентированный» все же относится в первую очередь к базам данных (MongoDB самая популярная), а не к модели данных. Но я считаю, что упомянуть все же надо. К тому же, в условном PostgreSQL, который является реляционной базой, вы можете сделать документориентированную модель.

В документориентированных базах данные хранятся в виде JSON, которые и называются документами. JSON, как вы знаете, может обладать любой структурой и уровнем вложенности, что максимально удобно для разработки приложений и хранения метаданных.

Пример запроса в MongoDB:

db.orders.find({ price: { $gt: 500 } })

Здесь мы ищем товары, которые дороже 500 баксов.

Плюсы

  • Скорость разработки, ведь документы JSON идеально маппятся на объекты в коде. Разработчикам не нужно тратить время на проектирование сложных схем заранее. Они все равно потом с высокой вероятностью поменяются.

  • Динамическая схема, которую вы можете изменять «на лету»

  • Раз легко добавлять изменения, то и масштабировать весьма просто

Минусы

  • Из-за отсутствия схемы, приходится реализовывать на уровне приложения дополнительные проверки, что необходимые данные не отсутствуют

  • Весьма большой риск «болота данных». Частая проблема любых неструктурированных данных.

  • Избыточность данных, потому что никакой нормализации

Когда применяется?

В системах с высокой скоростью изменений и непредсказуемой структурой данных: управление каталогами товаров (где у каждого товара свои характеристики), системы контента (блоги, соцсети). Идеальный выбор для микросервисов, где каждому сервису нужна своя независимая и гибкая база. Совершенно не подходит для аналитических решений.

Примечание: есть еще такой подход key-value, весьма похожий на документоориентированный. Только там по ключу можно получить все, что угодно, а не только JSON. Описывать его отдельно я не буду.

Графовая

Поговорив про документоориентированные базы, мы не можем не поговорить про графовые. Снова нужно подсветить, что слово «графовый» относится не к модели данных, а к специализированным базам.

Графовая модель удобна для моделирования сложных взаимосвязей, таких как социальные сети, рекомендации, причинно-следственные цепочки и логистические маршруты.

Основными элементами модели являются:

  • Узлы (Nodes) — сущности (например, «Клиент», «Счет», «Телефон»).

  • Связи (Relationships/Edges) — линии, соединяющие узлы и имеющие направление и тип (например, «ВЛАДЕЕТ», «ПЕРЕВЕЛ»).

  • Свойства (Properties) — атрибуты, которые можно вешать как на узлы, так и на сами связи.

  • Метки (Labels) — способ группировки узлов по типам

Пример запроса (на языке Cypher): Поиск подозрительной цепочки, где разные клиенты указали один и тот же номер телефона.

MATCH (c1:Customer)-[:HAS_PHONE]->(p:Phone)<-[:HAS_PHONE]-(c2:Customer)
WHERE c1 <> c2
RETURN c1.name, c2.name, p.number;

Традиционно напишу про плюсы и минусы, хотя этот подход для конкретных задачах и его нельзя сравнивать, скажем, с какой-нибудь «Звездой».

Плюсы

  • Скорость обхода связей, потому как поиск на глубину 5–10 рукопожатий в графе занимает миллисекунды. В обычных СУБД было бы куча join-ов.

  • Гибкость, так как легко создавать новые объекты и связи.

Минусы

  • Очень высокий порог входа, ведь нужно полностью перестроить восприятие данных, если привыкли работать с таблицами.

  • Сложная масштабируемость, так как распределять огромный связный граф по разным серверам (шардирование) технически намного сложнее, чем независимые таблицы.

Когда применяется?

Там, где ценность скрыта во взаимоотношениях: в системах антифрода (поиск цепочек отмывания денег), в социальных сетях (рекомендации друзей), в мастер-данных (MDM) или в сложных иерархиях и логистических маршрутах.

Итого

Как видно, не только звездой и DataVault богаты. Хотя действительно именно эти две методологии используются чаще всего. Но это не означает, что не нужно разбираться в других способах, как организовать свои данные.

Пишу в телеграме краткие обзоры статей, исследований, новостей и другого на тему данных и AI.