Star schema vs snowflake schema

Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.

Короткий ответ

  • Star schema (звезда) — fact в центре, dimension вокруг, dimension денормализованы
  • Snowflake schema (снежинка) — то же, но dimension нормализованы на под-dimension

В DWH в 95% случаев побеждает star — быстрее, проще, понятнее.

Визуально

Star schema

     dim_users
          |
dim_date  |  dim_stores
    \     |     /
     fact_orders
         /
   dim_products

Одно fact в центре, 4 dimension вокруг — напоминает звезду.

Snowflake schema

                  dim_country
                       |
dim_users ------- dim_city
    |
fact_orders                dim_category ----- dim_department
    |                           |
dim_products  -----------------

Dimension имеет свои «подветки» — получается снежинка.

Пример star schema

-- dimension: products (ОДНА таблица, денормализованная)
CREATE TABLE dim_products (
    product_id INT PRIMARY KEY,
    name VARCHAR(200),
    category VARCHAR(100),         -- повторяется для товаров в одной категории
    category_description TEXT,
    department VARCHAR(50),        -- повторяется
    department_manager VARCHAR(100)
);

-- fact: orders
CREATE TABLE fact_orders (
    order_id INT PRIMARY KEY,
    product_id INT REFERENCES dim_products(product_id),
    user_id INT,
    date_id INT,
    amount DECIMAL(10,2)
);

Запрос:

SELECT p.category, SUM(f.amount) AS revenue
FROM fact_orders f
JOIN dim_products p ON p.product_id = f.product_id
GROUP BY p.category;

Один JOIN — просто и быстро.

Пример snowflake schema

-- dimension разбита на 3 нормализованные таблицы
CREATE TABLE dim_departments (
    department_id INT PRIMARY KEY,
    department VARCHAR(50),
    manager VARCHAR(100)
);

CREATE TABLE dim_categories (
    category_id INT PRIMARY KEY,
    category VARCHAR(100),
    description TEXT,
    department_id INT REFERENCES dim_departments(department_id)
);

CREATE TABLE dim_products (
    product_id INT PRIMARY KEY,
    name VARCHAR(200),
    category_id INT REFERENCES dim_categories(category_id)
);

Запрос на те же данные:

SELECT c.category, SUM(f.amount) AS revenue
FROM fact_orders f
JOIN dim_products p   ON p.product_id = f.product_id
JOIN dim_categories c ON c.category_id = p.category_id
GROUP BY c.category;

Два JOIN вместо одного.

Сравнение

Критерий Star Snowflake
Нормализация денормализован нормализован
JOIN в запросах меньше больше
Размер хранилища больше (дубли) меньше
Производительность запросов быстрее медленнее
Понятность для BI-инструментов высокая средняя
Риск data inconsistency выше ниже
Время загрузки ETL быстрее медленнее
Применимость в DWH стандарт редко

Почему star выигрывает в DWH

1. Запросы проще

Bi-аналитик пишет SQL. JOIN product ON ... — один. vs два-три JOIN в snowflake.

2. Быстрее

DWH любит большие denormalized таблицы. Колоночные движки (ClickHouse, BigQuery) оптимизированы под широкие fact/dim.

3. BI-tools работают лучше

Tableau, Looker, Power BI плохо догоняют сложные joins. Star понятнее инструменту.

4. Storage уже не проблема

Дубли category в 10K продуктах — 10K раз слово «Electronics». Это секунды хранилища в 2026 году.

5. ETL проще

Загрузка одной denormalized таблицы проще, чем трёх связанных.

Когда snowflake имеет смысл

Очень большие dimensions с частыми обновлениями

Если в dimension 100 колонок и часто меняется — snowflake даёт контроль.

Regulatory compliance

Для финансовой отчётности иногда требуется нормализация (аудит, правила).

Шарируемые подDimensions

Если dim_geography используется в 5 fact-таблицах → выносим отдельно (это близко к snowflake).

Legacy-системы OLTP

В OLTP нормализация важна. Но это не DWH.

Гибрид: galaxy / constellation schema

Несколько fact-таблиц, разделяющих общие dimensions.

fact_orders ---+--- dim_date
               |
fact_clicks ---+

Несколько «звёзд», связанных через shared dimensions. Реальные DWH обычно такие.

Практика проектирования

Начать со star

Всегда сначала star. Если упрётесь в проблему — можно перейти к snowflake.

SCD2 для changing dimensions

Если dimension меняется (user переехал, product сменил цену) — SCD2 с valid_from/valid_to.

Широкие fact-таблицы

Включить в fact самые часто нужные колонки из dim через denormalization. Меньше JOIN на runtime.

Conformed dimensions

Общие dimensions между fact-таблицами. dim_date одна на все, не повторять.

На собесе

Вопрос: «Какая схема лучше?»

Хороший ответ:

  • Star почти всегда (простота, скорость)
  • Snowflake — если dimensions большие и часто меняются
  • Важнее знать, когда применять SCD, чем идеологически выбирать

Вопрос: «В чём проблема snowflake?»

  • Лишние JOIN → медленнее запросы
  • BI-инструменты с ними хуже работают
  • Типичная задача выражается через 5 JOIN вместо 2

Частые ошибки

Ошибка 1. Смешивать OLTP и DWH подходы

В OLTP-Postgres — 3NF нормализация. В DWH — star denormalized. Разные цели.

Ошибка 2. Делать snowflake из моды

«Нормализация — правильно» — принцип из 80-х. В DWH это вредит.

Ошибка 3. Star без SCD

Denormalized dim без обработки изменений → потеря истории.

Ошибка 4. Очень широкие fact-таблицы (100+ колонок)

Граница между полезной denormalization и бардаком. Здравый смысл важен.

Связанные темы

FAQ

Star или snowflake для аналитики?

Star в 95% случаев. Snowflake только при конкретных причинах.

Можно ли смешивать?

Да — galaxy / constellation schema. Часть dimensions денормализованы, часть нет.

Star — это про Kimball?

Да, Ralph Kimball — автор подхода. «Dimensional modeling» = star schema подход.

Snowflake лучше для data lake?

Data lake вообще обычно без жёсткой схемы (schema-on-read). Star/snowflake — для структурированного DWH.


Тренируйте data modelling — откройте тренажёр с 1500+ вопросами для собесов.