Ответ
Снежинка (snowflake) — это нормализованная схема хранения данных в хранилище (DWH), которая является расширением схемы "звезда" (star schema). В ней таблицы измерений (dimensions) дополнительно нормализуются, разбиваясь на иерархические связанные таблицы.
Да, схема "снежинка" по определению находится в 3NF (Third Normal Form), а часто и в BCNF. Это ее ключевое отличие от "звезды", где измерения денормализованы.
Условия 3NF:
- Таблица находится во 2NF (нет частичных зависимостей от составного ключа).
- Нет транзитивных зависимостей (неключевые атрибуты зависят только от первичного ключа, а не от других неключевых атрибутов).
Пример нарушения 3NF и исправления через "снежинку":
-- Таблица 'orders' с нарушением 3NF (customer_city зависит от customer_id, а не от order_id):
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
customer_name VARCHAR(100),
customer_city VARCHAR(100), -- Транзитивная зависимость: city зависит от customer_id
order_date DATE
);
-- Приведение к 3NF / Схема "снежинка":
CREATE TABLE dim_customer (
customer_id INT PRIMARY KEY,
customer_name VARCHAR(100),
city_id INT REFERENCES dim_city(city_id) -- Вынос в отдельную таблицу
);
CREATE TABLE dim_city (
city_id INT PRIMARY KEY,
city_name VARCHAR(100),
region_id INT REFERENCES dim_region(region_id) -- Дальнейшая нормализация
);
CREATE TABLE fact_orders (
order_id INT PRIMARY KEY,
customer_id INT REFERENCES dim_customer(customer_id),
order_date DATE
);
Преимущество снежинки — уменьшение избыточности данных и согласованность. Недостаток — более сложные запросы с большим количеством JOIN, что может влиять на производительность.
Ответ 18+ 🔞
Давай разберём эту вашу снежинку, а то я смотрю, у некоторых уже глаза на лоб лезут от этих нормальных форм. Слушай сюда, история простая, как три копейки.
Представь, что у тебя есть главная таблица с заказами — orders. И ты туда, такой умный, запихнул всё подряд: и номер заказа, и имя клиента, и его город. Ну и что? А то, что этот город привязан не к заказу, а к клиенту! Это ж классическая транзитивная зависимость, ёпта. Получается, если один Вася Пупкин из Москвы сделает сто заказов, ты эту самую Москву в базе продублируешь сто раз. Идиотизм? Да, овердохуища идиотизма! Данные избыточные, место зря жрёшь, а если Москву переименуют в Мухосранск — тебе придётся лазить по всем ста записям и править. Волнение ебать, честное слово.
Вот тут-то и выруливает наша снежинка. Её главный принцип — разнести всё по полочкам. Берёшь эту кучу-малу и начинаешь нормализовать до состояния 3NF.
Что такое 3NF, если по-простому?
- Нету такого, чтобы часть данных зависела только от кусочка ключа (это уже 2NF, но проехали).
- Самое важное: чтобы неключевые поля (типа города) зависели только от первичного ключа своей таблицы, а не от какого-то другого поля рядом. Как в нашем примере:
customer_cityзависел не отorder_id, а отcustomer_id. Это нарушение, товарищ!
Как это лечится? Да элементарно, Ватсон! Выносим клиента в отдельную таблицу dim_customer. А город клиента? А город — это вообще отдельная сущность! Выносим и его в таблицу dim_city. Получается такая разветвлённая, иерархическая хуйня, где всё связано ссылками. Смотри на код, тут всё наглядно:
-- Было плохо (город прилип к заказу через клиента):
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
customer_name VARCHAR(100),
customer_city VARCHAR(100), -- Нарушение! Город зависит от клиента, а не от заказа.
order_date DATE
);
-- Стало хорошо (снежинка в 3NF):
-- Сначала справочник городов
CREATE TABLE dim_city (
city_id INT PRIMARY KEY,
city_name VARCHAR(100)
);
-- Потом справочник клиентов, который ссылается на город
CREATE TABLE dim_customer (
customer_id INT PRIMARY KEY,
customer_name VARCHAR(100),
city_id INT REFERENCES dim_city(city_id) -- Ссылка, а не дубль текста!
);
-- И наконец, главная таблица фактов, чистая и аккуратная
CREATE TABLE fact_orders (
order_id INT PRIMARY KEY,
customer_id INT REFERENCES dim_customer(customer_id), -- Ссылка на клиента
order_date DATE
);
И что мы имеем в сухом остатке?
- Плюсы: Избыточность данных — ноль ебать. Москва хранится в одном-единственном месте. Консистентность — на высоте. Захотел поменять название региона — поправил в одной записи
dim_city, и оно автоматом ко всем клиентам применилось. Удивление пиздец, как удобно. - Минусы: Запросы становятся пиздопроебибными. Чтобы получить сводный отчёт, тебе придётся делать
JOINна столько таблиц, что голова кругом пойдёт.fact_orders->dim_customer->dim_city... Производительность на больших данных может накрыться медным тазом, если индексы не продуманы.
Так что выбирай, чувак: хочешь целостность данных и экономию места — снежинка твой выбор. Хочешь, чтобы аналитики не матерились, собирая отчёт, — возможно, классическая звёзда с её денормализацией будет практичнее. Всё зависит от задачи, да похуй, в общем-то, на чистоту теории, если на практике всё тормозит.