Learning Platform
Глоссарий Troubleshooting
Урок 18.02 · 18 мин
Начальный
one-big-tabledenormalizationwide-tables

One Big Table и wide tables

В прошлом уроке мы сказали: на gold-слое medallion живут либо star schema, либо One Big Table (OBT). Star schema вы уже знаете из модулей про размерное моделирование. OBT — подход, который стал популярен именно с приходом колоночных cloud-warehouse, и он напрямую бросает вызов привычке всегда разносить данные по таблицам. Этот урок разбирает, что такое OBT, в чём её компромисс и где её место.

One Big Table — это одна широкая денормализованная таблица, в которой собраны все факты и все описательные атрибуты сразу. Никаких отдельных dimension-таблиц, никаких JOIN на чтении. Всё, что аналитику может понадобиться для запроса, лежит в одной таблице — отсюда и название «одна большая таблица». Синоним — wide table, «широкая таблица».


Как выглядит OBT рядом со star schema

Возьмём знакомую картину. В star schema есть fct_orders с foreign keys и несколько dimensions: dim_customer, dim_product, dim_date. Чтобы получить «выручку по городам клиентов и категориям товаров», аналитик соединяет fact с тремя dimensions.

OBT берёт ту же информацию и разворачивает её в одну таблицу: атрибуты клиента, атрибуты товара, атрибуты даты — всё дописано прямо в строку рядом с метриками.

-- Star schema: fact + JOIN к dimensions на каждый запрос
SELECT c.city, p.category, SUM(f.amount)
FROM fct_orders f
JOIN dim_customer c ON f.customer_key = c.customer_key
JOIN dim_product  p ON f.product_key  = p.product_key
GROUP BY c.city, p.category;

-- One Big Table: всё в одной таблице, ноль JOIN
SELECT customer_city, product_category, SUM(amount)
FROM obt_orders
GROUP BY customer_city, product_category;

Структурно obt_orders — это fct_orders, в которую «влиты» все нужные столбцы из всех dimensions:

CREATE TABLE obt_orders (
    order_id           BIGINT,
    order_date         DATE,
    -- метрики (бывшая fact-таблица):
    amount             DECIMAL(12,2),
    quantity           INTEGER,
    -- атрибуты клиента (бывший dim_customer):
    customer_id        BIGINT,
    customer_name      VARCHAR,
    customer_city      VARCHAR,
    customer_segment   VARCHAR,
    -- атрибуты товара (бывший dim_product):
    product_name       VARCHAR,
    product_category   VARCHAR,
    product_brand      VARCHAR,
    -- атрибуты даты (бывший dim_date):
    order_year         INTEGER,
    order_month        INTEGER,
    order_weekday      VARCHAR
);
Star schema против One Big Table
dim_customerОтдельная dimension-таблица с атрибутами клиента
fct_ordersFact-таблица с метриками и foreign keys к dimensions
dim_productОтдельная dimension-таблица с атрибутами товара
денормализация: dimensions влиты в fact
obt_ordersОдна широкая таблица: метрики и все атрибуты всех dimensions вместе. JOIN на чтении не нужен

Почему OBT стала возможна: колоночное хранение

OBT — не новая идея сама по себе (это просто крайняя денормализация), но практичной её сделали именно колоночные cloud-warehouse: Snowflake, BigQuery, Redshift, Databricks. Чтобы понять почему, вспомните физику колоночного хранения из модуля про OLTP и OLAP.

В колоночном хранилище каждый столбец лежит на диске отдельно. Когда запрос обращается к трём столбцам из ста — warehouse читает ровно эти три, остальные 97 не трогает вообще. Поэтому «широта» таблицы почти не вредит: лишние столбцы не замедляют запрос, который их не использует. В строковом хранилище было бы иначе — там читается строка целиком.

Именно это и переворачивает старую интуицию. В мире строкового хранения (классический OLTP) широкая таблица — это плохо: каждое чтение тащит с диска все сто столбцов, даже когда нужны три. Поэтому реляционная школа учила разносить данные по узким таблицам. Колоночное хранение убирает этот штраф: в нём ширина таблицы и стоимость запроса развязаны. OBT — это идея, которая была бы вредной на строковом движке и стала разумной на колоночном. Это хороший пример общего принципа курса: «правильность» модели не абсолютна, она зависит от физики хранилища под ней. Сменилась физика — сменилось и то, какая модель хороша.

Это снимает главное возражение против OBT. «Таблица со ста столбцами» на колоночном движке — нормально: платите чтением только за то, что реально читаете. А выигрыш — отсутствие JOIN — реален: JOIN это работа (хеш-таблицы, сопоставление ключей), и убрать его означает ускорить запрос.

Замеры это подтверждают. По бенчмаркам Fivetran, на Redshift, Snowflake и BigQuery переход со star schema на OBT даёт прирост скорости запросов примерно на 25-50% (на BigQuery — около 49%). Цифры зависят от движка и нагрузки, но направление устойчивое: на колоночных warehouse OBT обычно быстрее star schema.


Компромисс: storage против compute

Раз OBT быстрее — почему не делать всегда только OBT? Потому что у скорости есть цена. OBT — это классический компромисс storage против compute.

OBT экономит compute: запрос не тратит вычисления на JOIN. Но платит storage: данные дублируются. Атрибут customer_city в star schema хранится один раз — в dim_customer, в одной строке на клиента. В OBT он повторяется в каждой строке заказа этого клиента. Если у клиента 500 заказов, его город записан 500 раз.

Компромисс OBT: за что платим, что выигрываем
Star schemaАтрибут dimension хранится один раз. На чтении нужен JOIN — тратится compute
денормализация
One Big TableАтрибут продублирован в каждой строке факта. JOIN не нужен — экономится compute

На колоночных warehouse этот компромисс часто выгоден для OBT по двум причинам. Первая: storage дёшев, а колоночное сжатие отлично справляется с дублированием. Столбец customer_city, где одно значение повторяется тысячи раз подряд, сжимается почти до нуля (повторы — лучший случай для сжатия). Вторая: compute дорог и его экономия — это деньги и время на каждый запрос. Платить дешёвым storage, чтобы сэкономить дорогой compute, — разумная сделка. Но «часто выгоден» не значит «всегда»: на очень больших объёмах или редко запрашиваемых данных арифметика может склониться обратно.

АспектStar schemaOne Big Table
JOIN на чтенииНуженНе нужен
Дублирование атрибутовНетЕсть (в каждой строке)
StorageМеньшеБольше (но хорошо сжимается)
Compute на запросБольше (JOIN)Меньше
Скорость на колоночном warehouseБазоваяОбычно +25-50%

Слабые места OBT: историчность и backfill

У OBT есть проблемы серьёзнее, чем дублирование, и о них надо знать.

Историчность dimension. Вспомните SCD2: атрибуты dimension меняются во времени, и нужно хранить версии. В star schema это решено элегантно — SCD2 в dim_customer, fact ссылается на нужную версию. В OBT отдельной dimension нет. Атрибуты «вшиты» в строку факта, и момент записи факта фиксирует значение атрибута на тот момент. Это иногда удобно (видно состояние «как было»), но управлять историей сложнее: нет одного места, где живёт «текущая версия» клиента, и нет лёгкого способа спросить «как выглядит клиент сейчас» отдельно от заказов.

Backfill при добавлении атрибута. Это, пожалуй, главная боль OBT. В star schema добавить новый атрибут клиента — это ALTER TABLE dim_customer ADD COLUMN и заполнение одной dimension. В OBT тот же атрибут нужно дописать в каждую строку таблицы заказов — а это могут быть миллиарды строк. Такой пересчёт всей таблицы называется backfill, и он дорогой: добавление одного столбца превращается в перезапись всего OBT.

WARNING

Эти два минуса — историчность и backfill — причина, по которой OBT редко используют как источник истины. Если витрина живёт долго и часто эволюционирует (новые атрибуты, меняющиеся dimensions), цена backfill и сложность с историей накапливаются. Star schema или нормализованная модель переживают эволюцию заметно легче.

Физика OBT в ClickHouse — почему wide table быстрее star schema на колоночном движке

Где место OBT: производная, не источник истины

Отсюда — современная позиция индустрии. OBT — это не замена размерному моделированию и не источник истины. OBT — это downstream-производная для потребления.

Правильный паттерн такой: источник истины — нормализованный или размерный слой (3NF/Data Vault на silver, star schema на gold). А OBT строится из этого слоя как финальная, удобная для чтения «материализация» под конкретные паттерны запросов или под конкретный BI-инструмент.

-- OBT не источник истины: она СОБИРАЕТСЯ из star schema
CREATE TABLE obt_orders AS
SELECT
    f.order_id, f.order_date, f.amount, f.quantity,
    c.customer_name, c.customer_city, c.customer_segment,
    p.product_name, p.product_category, p.product_brand
FROM fct_orders f
JOIN dim_customer c ON f.customer_key = c.customer_key
JOIN dim_product  p ON f.product_key  = p.product_key;

JOIN выполняется один раз при сборке OBT, а не на каждый пользовательский запрос. Star schema остаётся источником истины — там удобно управлять историей и добавлять атрибуты. OBT — её быстрая проекция для чтения. Если OBT испортилась или паттерн запросов изменился — её пересобирают из star schema. Это та же логика, что у PIT/bridge в Data Vault: предвычисленный кэш поверх честного источника истины.

Так разрешается мнимое противоречие «OBT против star schema». Это не «или-или»: star schema — источник истины, OBT — производная витрина потребления поверх неё. В следующем уроке посмотрим, как dbt — стандартный инструмент трансформаций — организует эти слои.


Попробуй сам

  1. Возьмите star schema из модулей про размерное моделирование (fct_orders + dim_customer + dim_product + dim_date). Спроектируйте на бумаге соответствующую obt_orders: выпишите все столбцы.
  2. Посчитайте дублирование: если у клиента 500 заказов, сколько раз его customer_city хранится в star schema и сколько — в OBT? Почему колоночное сжатие делает это не страшным?
  3. Представьте, что нужно добавить атрибут customer_loyalty_tier. Опишите, что это за операция в star schema и что — в OBT (вспомните слово backfill).
  4. Сформулируйте в двух предложениях, почему OBT строят ИЗ star schema, а не наоборот.

Проверка знанийKnowledge check
В чём состоит компромисс storage-vs-compute у One Big Table, почему он часто выгоден на колоночных warehouse, и почему OBT строят как производную от star schema, а не как источник истины?
ОтветAnswer
One Big Table — это одна широкая денормализованная таблица, где все факты и все атрибуты dimensions собраны вместе, без JOIN на чтении. Компромисс storage-vs-compute: OBT экономит compute (запрос не тратит вычисления на JOIN), но платит storage (атрибуты dimensions дублируются — например, город клиента повторяется в каждой строке его заказов). На колоночных warehouse этот компромисс часто выгоден: storage дёшев, а колоночное сжатие отлично справляется с повторяющимися значениями (повторы — лучший случай для сжатия), тогда как compute дорог и его экономия ценна на каждом запросе; по бенчмаркам OBT даёт прирост скорости примерно на 25-50%. Но OBT редко делают источником истины из-за двух слабых мест: историчность dimension хуже управляется (нет отдельной dimension с SCD2), и добавление нового атрибута требует backfill — дописывания столбца в каждую строку, то есть перезаписи всей таблицы из миллиардов строк. Поэтому правильный паттерн: источником истины остаётся нормализованный или размерный слой (star schema), где удобно управлять историей и эволюцией, а OBT строится из него как downstream-производная — быстрая read-оптимизированная проекция, где JOIN выполнен один раз при сборке. OBT и star schema не конкурируют: star schema — источник истины, OBT — производная витрина потребления.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Что такое One Big Table (OBT)?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5