Data Vault 2.0 deep dive на собеседовании Data Engineer

Проверь себя · 1/3разбор после ответа
Есть таблицы payments(user_id) и refunds(user_id). Нужно получить пользователей, у которых был платёж, но не было ни одного возврата. Какой запрос корректнее всего описывает задачу?

Эта статья — про продвинутый Data Vault 2.0, а не про азы. Предполагается, что вы уже знаете, что такое hub (бизнес-ключ), link (связь между ключами) и satellite (описательные атрибуты с историей). Если нет — начните с базовой статьи Data Vault 2.0 для DE, а сюда возвращайтесь за глубиной: слои архитектуры, hash-ключи, таблицы-ускорители запросов (PIT и bridge) и ghost-записи. Именно эти темы отделяют кандидата, который «читал про DV», от того, кто его строил.

Три слоя: Raw, Business, Information Mart

Data Vault 2.0 — это не только моделирование, но и слоистая архитектура хранилища. На собесе часто просят объяснить, зачем нужны три слоя и что в каждом можно, а что нельзя.

Raw Vault — прямая загрузка из источников. Данные грузятся как есть, без применения бизнес-правил: только структурируются в hub, link и satellite. Ключевой принцип — insert-only (только вставка, без UPDATE и DELETE). Каждая загрузка добавляет новые строки, старые не трогаются. Это даёт полную аудитируемость: видно, что и когда пришло из источника, и хранилище можно воспроизвести на любую дату.

Business Vault — производный слой с вычисленными структурами и мягкими бизнес-правилами (soft rules). Здесь считают то, чего нет в источнике напрямую: агрегаты, дедупликацию, приведение к единой бизнес-логике, вычисляемые сателлиты. Сюда же обычно относят таблицы-ускорители запросов — PIT и bridge. Важно: жёсткие правила (hard rules), которые могут изменить или потерять данные, в Raw Vault не применяют — их место здесь.

Information Mart — витрина под потребление: денормализованная схема (обычно star schema), готовая для BI. Часто это вьюхи поверх Raw и Business Vault, а не отдельные физические таблицы. Именно на этот слой ходят аналитики и дашборды.

Смысл разделения — у каждого слоя своя ответственность: Raw хранит правду источника, Business применяет логику, Mart отдаёт данные пользователю. Меняется бизнес-правило — переписываете Business Vault, не трогая сырьё.

Hash-ключи и hashdiff

Главное отличие DV2.0 от DV1.0 — переход с последовательных суррогатных ключей на hash-ключи. Ключ считается как хеш от бизнес-ключа, и это даёт две вещи: детерминированность (одинаковый бизнес-ключ всегда даёт один и тот же hash на любой системе) и возможность грузить hub, link и satellite параллельно, не дожидаясь генерации суррогатных ключей и не делая lookup. На MPP-платформах это критично для скорости загрузки.

hub_customer:
  customer_hk = MD5(customer_id)   -- hash-ключ = хеш бизнес-ключа
  customer_id                       -- сам бизнес-ключ
  load_dt                           -- когда запись загружена
  record_source                     -- откуда пришла

Hashdiff — хеш от всех описательных атрибутов сателлита. Нужен, чтобы понять, изменилась ли запись, без сравнения колонка за колонкой. При загрузке считаете hashdiff новой версии и сравниваете с последним для этого ключа: совпал — данные те же, ничего не вставляем; отличается — появилась новая версия, добавляем строку.

sat_customer:
  customer_hk
  load_dt
  hashdiff = MD5(name || email || phone)   -- изменился → новая версия записи
  name, email, phone

На собесе про хеши любят копать: какой алгоритм брать. MD5 исторически стандарт (компактный, быстрый), но у него есть риск коллизий, поэтому на больших объёмах и там, где важна безопасность, берут SHA-256. Ещё частый вопрос — как считать hashdiff консистентно: приводить значения к строке единообразно, обрабатывать NULL (например, заменять на пустую строку или специальный маркер) и использовать разделитель между полями, чтобы ('ab','c') и ('a','bc') не давали одинаковый хеш.

Point-in-Time таблицы

У одного hub может быть много сателлитов, и каждый обновляется в свои моменты времени. Чтобы получить состояние сущности «как было на дату T», пришлось бы join'ить все сателлиты с коррелированными подзапросами «возьми последнюю версию до T» — это медленно и уродливо.

PIT-таблица (Point-in-Time) решает это: заранее просчитывает для каждого бизнес-ключа на каждую снимок-дату, какая именно версия (load_dt) каждого сателлита была актуальна в тот момент. Это таблица-ускоритель из Business Vault: сами данные она не хранит, только указатели на нужные версии сателлитов.

CREATE TABLE pit_customer (
  customer_hk,        -- ключ сущности
  snapshot_dt,        -- дата снимка
  sat_personal_dt,    -- какая версия sat_personal актуальна на snapshot_dt
  sat_address_dt,     -- какая версия sat_address
  sat_account_dt      -- какая версия sat_account
);

После этого запрос состояния на дату превращается в простые equi-join'ы: берёте строку PIT на нужную дату и джойните сателлиты по паре (customer_hk, load_dt). Никаких подзапросов «найди максимум» — отсюда и скорость.

Bridge-таблицы

Bridge-таблица — второй тип ускорителя запросов. Она заранее просчитывает пути обхода через несколько hub и link, чтобы не делать множество join'ов на лету при работе со связями «многие ко многим».

Когда сущности связаны цепочкой (клиент → заказ → товар → категория), навигация по нескольким link на каждом запросе стоит дорого. Bridge собирает нужные комбинации ключей в одну таблицу, часто с предагрегацией по путям, и запрос вместо десятка join'ов делает один-два. Как и PIT, bridge живёт в Business Vault и периодически пересчитывается снапшотами.

Готовишься к собесу Data Engineer?
Spark, Airflow, ClickHouse, SQL для DE — вопросы с разборами в Telegram
Тренировать DE в Telegram

Ghost- и unknown-записи

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

ghost-запись в сателлите:
  customer_hk = '00000000000000000000000000000000'
  load_dt     = '1900-01-01'
  hashdiff    = '00000000000000000000000000000000'
  name = 'Unknown', email = 'Unknown', ...

Зачем это нужно. Во-первых, PIT и bridge могут ссылаться на ghost-запись, и тогда join к сателлиту всегда что-то находит — outer join превращается в inner, без NULL и без пропущенных строк. Во-вторых, в витринах ghost играет роль «unknown / not applicable» для внешнего ключа: аналитик видит явное «Неизвестно» вместо пустоты, а COUNT и GROUP BY не ломаются на NULL. Иногда различают zero key (запись ещё не приехала) и ghost record (осознанная заглушка-плейсхолдер), но идея одна — избавиться от NULL-join'ов и упростить запросы.

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

  • Применять бизнес-правила в Raw Vault. Raw должен хранить правду источника insert-only. Любая трансформация, которая может исказить или потерять данные, — это hard rule, ей место в Business Vault. Иначе теряется аудитируемость.
  • Считать hashdiff без учёта NULL и разделителя. Без единого маркера для NULL и разделителя между полями конкатенация даёт ложные совпадения или ложные изменения — история сателлита едет.
  • Игнорировать риск коллизий MD5. На собесе почти всегда спрашивают про выбор алгоритма. Ответ «всегда MD5» без упоминания коллизий и альтернативы SHA-256 звучит поверхностно.
  • Путать PIT и bridge с хранением данных. Это ускорители запросов, а не источник истины: они только указывают на версии и пути, их всегда можно пересчитать из Raw/Business Vault.
  • Забывать про ghost-записи и получать NULL-join'ы. Без заглушек PIT/bridge при отсутствующем сателлите дают NULL, запросы усложняются, а агрегаты искажаются.

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

FAQ

Зачем в DV2.0 hash-ключи вместо суррогатных?

Hash-ключ детерминирован: одинаковый бизнес-ключ даёт один и тот же хеш на любой системе, без централизованной генерации последовательности. Это позволяет грузить hub, link и satellite параллельно и независимо, без lookup суррогатного ключа, что критично для скорости на MPP-платформах.

Чем PIT-таблица отличается от bridge?

PIT ускоряет запрос состояния одной сущности «на дату»: для каждого ключа и снимок-даты хранит указатели на актуальные версии её сателлитов. Bridge ускоряет навигацию между несколькими hub и link (связи «многие ко многим»), заранее просчитывая пути обхода. Обе — ускорители запросов в Business Vault, обе можно пересчитать.

MD5 или SHA-256 для хешей?

MD5 компактнее и быстрее, поэтому исторически стандарт в DV. Но у MD5 есть риск коллизий, поэтому на больших объёмах и там, где важна устойчивость к коллизиям, берут SHA-256 — ценой большего размера ключа. Правильный ответ на собесе — назвать trade-off, а не одну опцию.

Что такое ghost-запись и зачем она нужна?

Это заглушка в сателлите с хеш-ключом из нулей и дефолтной датой. Она позволяет PIT и bridge всегда находить строку в сателлите (outer join становится inner, без NULL) и служит значением «unknown / not applicable» в витринах, чтобы агрегаты и группировки не ломались на NULL.

Можно ли применять бизнес-логику прямо в Raw Vault?

Нет. Raw Vault грузится insert-only и хранит данные как есть, чтобы сохранить полную аудитируемость и воспроизводимость. Все вычисления, дедупликацию и приведение к единой бизнес-логике выносят в Business Vault, а витрины строят уже поверх обоих слоёв.

Это официальная информация?

Нет. Статья основана на методологии Data Vault 2.0 Дэна Линштедта, публичной документации и опыте инженеров. Конкретные реализации в компаниях отличаются деталями.


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