Learning Platform
Глоссарий Troubleshooting
Урок 15.02 · 17 мин
Начальный
scd-type-0scd-type-1overwritedimension-design

Type 0 (retain) и Type 1 (overwrite)

В прошлом уроке мы увидели проблему: атрибуты dimension меняются, и от способа обработки изменения зависит достоверность отчётов. Начнём с двух простейших решений каталога SCD — Type 0 и Type 1. Оба не хранят историю изменений. И оба — не «плохие» или «урезанные» варианты, а корректные инженерные решения для атрибутов определённого рода.

Type 0 — для атрибутов, которые по своей природе не меняются вообще. Type 1 — для атрибутов, у которых меняется значение, но бизнес сознательно решает хранить только актуальное.


Type 0 — Retain original

SCD Type 0 означает: атрибут никогда не меняется. Если из источника приходит новое значение этого атрибута — оно игнорируется, исходное остаётся нетронутым.

Type 0 подходит для атрибутов, неизменных по своей сути. Дата рождения человека. Оригинальная дата открытия счёта. Дата первой регистрации пользователя. Номер VIN автомобиля. Эти значения зафиксированы в момент создания сущности и физически не могут стать другими — а если в источнике они «изменились», это почти наверняка исправление ошибки ввода, а не реальное изменение.

CREATE TABLE dim_customer (
    customer_key       INT PRIMARY KEY,
    customer_name      VARCHAR(120),
    date_of_birth      DATE,          -- Type 0: задаётся при создании, не меняется
    original_signup_date DATE,        -- Type 0: дата первой регистрации, неизменна
    email              VARCHAR(160),  -- (тип разберём ниже)
    city               VARCHAR(80)    -- (тип разберём в следующем уроке)
);

Механика Type 0 — это, по сути, отсутствие механики: ETL-процесс при загрузке просто не трогает Type 0-столбцы существующих строк. Значение записывается ровно один раз — в момент создания строки dimension — и дальше остаётся неприкосновенным навсегда.

Тонкий момент: что делать, если из источника всё-таки пришло другое значение Type 0-атрибута? Например, в системе исправили дату рождения клиента. Type 0 предписывает это новое значение проигнорировать. Логика в том, что для по-настоящему неизменного атрибута «другое значение из источника» — это либо исправление давней опечатки, либо ошибка источника, и автоматически принимать его опасно: можно затереть верное значение неверным. На практике такие расхождения обычно не молча игнорируют, а логируют для разбора человеком — но в саму dimension они не попадают. Type 0 — это утверждение «этот столбец менять нельзя», и ETL его соблюдает строго.

-- При обновлении клиента Type 0-столбцы НЕ участвуют в SET
UPDATE dim_customer
SET email = :new_email          -- обновляем
    -- date_of_birth НЕ трогаем: это Type 0
WHERE customer_key = :id;
Type 0: входящее изменение игнорируется
Источник: новое значениеИз source-системы пришло новое значение Type 0-атрибута. Обычно это исправление опечатки, а не реальное изменение.
игнорируется
dim: значение не меняетсяETL не включает Type 0-столбцы в UPDATE. Исходное значение, заданное при создании строки, остаётся.

История для Type 0 не нужна — её и нечего хранить, ведь значение по определению одно на всё время жизни сущности.

NOTE

Type 0 — это про неизменность по природе, а не про лень. Не путайте «атрибут не меняется» с «нам сейчас некогда обрабатывать изменение». Если атрибут реально меняется (адрес, должность), а вы объявили его Type 0 — вы будете молча терять реальные изменения. Type 0 законен только когда изменение атрибута невозможно по смыслу.


Type 1 — Overwrite

SCD Type 1 означает: при изменении атрибута старое значение перезаписывается новым. Хранится одна строка на сущность, в ней — всегда актуальное значение. Предыдущих значений не остаётся.

-- Type 1: прямая перезапись
UPDATE dim_customer
SET email = '[email protected]'
WHERE customer_key = 7012;
До UPDATE:
 customer_key | customer_name | email
--------------+---------------+----------------------
 7012         | Анна Петрова  | [email protected]

После UPDATE:
 customer_key | customer_name | email
--------------+---------------+----------------------
 7012         | Анна Петрова  | [email protected]

Старого email больше нет нигде. customer_key не изменился — все fact-строки, ссылающиеся на 7012, теперь «видят» новый email. Именно это поведение мы в прошлом уроке наблюдали как проблему — но там атрибутом был регион, важный для исторической отчётности. Ключевая мысль этого урока: для других атрибутов ровно то же поведение — это именно то, что нужно.

Стоит проговорить механику Type 1 с точки зрения хранилища. Перезапись — это обычный UPDATE одной строки: СУБД находит строку по customer_key, заменяет значение столбца. Никаких новых строк, никаких служебных дат, никакого роста таблицы. Dimension остаётся ровно того же размера — одна строка на сущность. Это самый дешёвый из всех SCD-типов и по объёму, и по сложности запросов: чтобы узнать значение атрибута, достаточно прочитать единственную строку клиента, без всякой фильтрации по датам или флагам. Простота — реальное достоинство Type 1, а не «то, чем приходится довольствоваться».


Type 1 — это сознательный выбор дизайна, а не дефект

Важно зафиксировать правильную рамку. Type 1 — не «урезанный Type 2», не «компромисс из-за нехватки ресурсов» и не признак плохого дизайна. Для целого класса атрибутов перезапись — намеренное и правильное проектное решение.

Type 1 уместен, когда бизнес сознательно решает: история изменений этого атрибута не нужна, важно только текущее значение. Когда такое решение разумно?

Исправление ошибок. Имя клиента было введено с опечаткой: «Анна Петорва». Опечатку исправляют на «Анна Петрова». Хранить «историю» опечатки бессмысленно и даже вредно — это не факт о клиенте, а дефект ввода. Здесь перезапись (Type 1) — единственно правильный выбор; Type 2 завёл бы фальшивую «версию» клиента.

Атрибуты, где значима только актуальность. Текущий контактный email, текущий телефон, текущий аватар. Для большинства бизнес-задач важно лишь, как связаться с клиентом СЕЙЧАС. Прошлые email-адреса аналитике не нужны — хранить их историю значит усложнять dimension ради данных, которые никто не запросит.

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

Атрибуты, где история избыточна для задач анализа. Иногда атрибут меняется, но ни один отчёт и ни одна метрика по его прошлым значениям не строятся. Например, ссылка на аватар клиента: она меняется, но «выручку по аватарам» никто не считает. Хранить историю аватаров — значит усложнять dimension ради данных, которые не будут запрошены. Type 1 здесь — экономия сложности без потери чего-либо ценного.

TIP

Решение «этот атрибут — Type 1» принимается так же серьёзно и осознанно, как решение «этот атрибут — Type 2». Вопрос не «можем ли мы себе позволить хранить историю», а «нужна ли история этого конкретного атрибута бизнесу для ответа на реальные вопросы». Если честный ответ — «нет», то Type 1 не компромисс, а правильный дизайн.

Surrogate key в dbt — как обновление Type 1 не ломает FK в fact-таблице

Цена Type 1: что нужно понимать осознанно

У Type 1 есть последствие, и грамотный инженер выбирает Type 1, понимая его. Поскольку старое значение исчезает, агрегаты, посчитанные по этому атрибуту, меняются задним числом.

Если регион клиента — Type 1, и клиент переехал из «Центра» в «Сибирь», то отчёт «продажи по регионам за прошлый январь», пересчитанный сегодня, отнесёт январские покупки уже к «Сибири». Вчерашняя и сегодняшняя версии одного и того же исторического отчёта разойдутся.

Для атрибута вроде email это не проблема: по email регионы продаж не считают. Для региона — проблема, и поэтому регион обычно делают Type 2. Вывод: цена Type 1 — невозможность воспроизвести исторический срез по этому атрибуту. Это приемлемо ровно тогда, когда такой срез никому не нужен.

Type 1: перезапись и её следствие
Type 1: UPDATE перезаписывает значениеСтарое значение атрибута заменяется новым. Одна строка на сущность, customer_key неизменен.
следствие
Исторические агрегаты по атрибуту меняютсяОтчёт за прошлый период, пересчитанный после изменения, отнесёт прошлые события к новому значению. Приемлемо, если такой срез не нужен.

Type 0 и Type 1 рядом

Оба типа дают одну строку на сущность и не хранят историю — но по разным причинам, и разница принципиальна.

АспектType 0 (retain)Type 1 (overwrite)
Меняется ли атрибутНет, неизменен по природеДа, но историю не хранят намеренно
Что делает ETL при новом значенииИгнорирует егоПерезаписывает старое
Строк на сущностьОднаОдна
Когда уместенДата рождения, VIN, дата созданияEmail, телефон, исправления опечаток
Почему истории нетЕё не существуетСознательно решили не хранить

Type 0 говорит: «менять нечего». Type 1 говорит: «менять есть что, но прошлое нам не нужно — нужно актуальное». Оба — полноправные, корректные решения каталога SCD.

Полезно зафиксировать, как принимать решение на практике. Идя по атрибутам dimension, для каждого задайте два вопроса подряд. Первый: «может ли этот атрибут вообще измениться?» Если нет — Type 0, дальше не думаем. Если да — второй вопрос: «нужна ли бизнесу история его изменений для каких-либо отчётов или анализа?» Если честный ответ «нет» — Type 1. Если «да» — это уже территория Type 2 и далее. Большинство атрибутов реальной dimension отвечают «нет» на второй вопрос: имена, контакты, мелкие технические признаки — для них Type 1 правильный выбор. Type 2 нужен меньшинству атрибутов — тем, чья история действительно используется. Не переоценивайте долю таких атрибутов: чрезмерное применение Type 2 — частая ошибка.

В следующем уроке перейдём к Type 2 — он, наоборот, хранит полную историю, и нужен для атрибутов вроде региона, где исторический срез критичен.


Попробуй сам

Дана dim_product: product_key, product_name, category, brand, weight_grams, manufacture_country, current_price.

  1. Для каждого атрибута определите Type 0 или Type 1 и обоснуйте. Подсказка: вес товара и страна производства физически зафиксированы при производстве; название и категория могут корректироваться.
  2. Напишите UPDATE, исправляющий опечатку в product_name. Объясните, почему здесь правильна именно перезапись, а не создание новой версии.
  3. Представьте, что category сделали Type 1, а потом понадобился отчёт «выручка по категориям за прошлый год». Что с ним не так? Какой это аргумент — за или против Type 1 для category?
  4. Сформулируйте словами: чем «атрибут не меняется» (Type 0) отличается от «атрибут меняется, но историю не храним намеренно» (Type 1).

Проверка знанийKnowledge check
Чем SCD Type 0 отличается от Type 1, и почему Type 1 (overwrite) следует считать осознанным проектным решением, а не дефектом или урезанной версией Type 2?
ОтветAnswer
SCD Type 0 (retain) означает, что атрибут никогда не меняется: новые значения из источника игнорируются, исходное остаётся. Он применяется к атрибутам, неизменным по природе — дата рождения, VIN, оригинальная дата открытия счёта; история не нужна, потому что значение по определению одно на всё время жизни сущности. SCD Type 1 (overwrite) означает, что атрибут меняется, но при изменении старое значение перезаписывается новым: одна строка на сущность, всегда актуальное значение, предыдущих не остаётся. Принципиальная разница: в Type 0 менять нечего, в Type 1 менять есть что, но историю сознательно решили не хранить. Type 1 — это не дефект и не урезанный Type 2, а намеренное и правильное проектное решение для целого класса атрибутов. Он уместен, когда бизнес осознанно решает, что история изменений конкретного атрибута не нужна: при исправлении опечаток (хранить "историю" опечатки в имени бессмысленно и вредно — это не факт о клиенте, а дефект ввода), для атрибутов, где значима только актуальность (текущий email, телефон), и для технических атрибутов. У Type 1 есть осознаваемая цена: поскольку старое значение исчезает, агрегаты по этому атрибуту меняются задним числом, и исторический срез по нему не воспроизвести. Грамотный инженер выбирает Type 1 именно тогда, когда такой срез бизнесу не нужен — и тогда это правильный дизайн, а не компромисс. Решение "атрибут — Type 1" принимается так же серьёзно, как "атрибут — Type 2".

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

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Что означает SCD Type 0 (retain original)?

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

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

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

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