Как декомпозировать широкую таблицу на сателлиты в Data Vault?

Ответ

В Data Vault 2.0 сателлиты (Satellites) хранят контекстные атрибуты и историю изменений для хабов (Hubs) или линков (Links). Широкую таблицу (wide table) декомпозируют по следующим принципам:

  1. Выделение сущностей (Hubs): Определите бизнес-ключи (например, CustomerID, OrderID) и создайте для них отдельные хабы.
  2. Выделение связей (Links): Если между ключами есть много-ко-многим отношения (например, Order-Product), создайте линк-таблицу.
  3. Группировка атрибутов по темпоральности и источнику (Satellites):
    • По скорости изменения: Атрибуты, меняющиеся с разной частотой (например, email vs last_login_date), можно вынести в разные сателлиты.
    • По источнику системы (Record Source): Атрибуты из разных систем-источников (CRM, ERP) размещаются в отдельных сателлитах. Это сохраняет трассируемость.
    • По семантической группе: Например, все адресные данные клиента (street, city, zip) — в один сателлит, демографические (birth_date, gender) — в другой.

Пример декомпозиции таблицы Customer:

-- Хаб
CREATE TABLE Hub_Customer (
    CustomerHashKey CHAR(32) PRIMARY KEY,
    CustomerID VARCHAR(50),
    LoadDate TIMESTAMP,
    RecordSource VARCHAR(20)
);

-- Сателлит с основными данными (из CRM)
CREATE TABLE Sat_Customer_Core (
    CustomerHashKey CHAR(32),
    LoadDate TIMESTAMP,
    FirstName VARCHAR(100),
    LastName VARCHAR(100),
    Email VARCHAR(255),
    HashDiff CHAR(32),
    PRIMARY KEY (CustomerHashKey, LoadDate)
);

-- Сателлит с адресом (из другой системы)
CREATE TABLE Sat_Customer_Address (
    CustomerHashKey CHAR(32),
    LoadDate TIMESTAMP,
    Street VARCHAR(200),
    City VARCHAR(100),
    Country VARCHAR(50),
    HashDiff CHAR(32),
    PRIMARY KEY (CustomerHashKey, LoadDate)
);

Такой подход повышает гибкость, упрощает загрузку новых источников и улучшает производительность, так как запросы часто затрагивают только нужные группы атрибутов.

Ответ 18+ 🔞

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

Смотри. Представь, что у тебя есть одна здоровенная, пиздопроебибна таблица Customer, куда ты годами сваливал всё подряд: и имя, и почту, и адрес, и когда он последний раз заходил. Куча всего. Потом ты смотришь на неё и понимаешь, что терпения ебать ноль — работать с этим монстром невозможно. Он как тот толстый мужик в автобусе, который занимает два места и всех зажимает.

Вот Data Vault 2.0 и предлагает не мучать себя, а аккуратно этого мужика разобрать на запчасти. По косточкам, блядь.

Первый шаг — найти скелет, основу. Это и есть хабы (Hubs). Ты выковыриваешь оттуда голые бизнес-ключи. CustomerID, OrderID — вот это вот всё. Это как паспортные данные. Просто номер и всё. Засовываешь их в отдельную маленькую табличку. Всё, скелет готов. Hub_Customer. Никаких лишних подробностей.

Второй шаг — разобраться со связями. Если у тебя в этой куче был завален заказ, а в нём — куча товаров (отношение "много-ко-многим"), то ты эту связку выносишь в отдельную таблицу — линк (Link). Link_Order_Product. По сути, это просто два ключа из хабов, которые дружат между собой. Как два чувака, которых свела судьба в одном линке.

А теперь самое интересное — мясо и одежда. Всё остальное, что было в той широкой таблице — это сателлиты (Satellites). И вот тут включается голова. Ты не скидываешь всё в одну кучу обратно, а группируешь по смыслу. Зачем? А затем, что так жить проще, ёпта!

  • Что меняется часто, а что редко? Почта у клиента может поменяться раз в пять лет, а дата последнего логина — каждый день. Тащить их вместе — это овердохуища лишних обновлений. Вынеси динамичные данные в один сателлит (last_login), а статичные — в другой (email, name). Запросы будут быстрее, и не нужно каждый раз читать про всё подряд.
  • Откуда ноги растут? Данные об имени пришли из CRM, а адрес — из отдельной системы доставки. Если смешать их в одну кучу, а потом в источнике адресов начнётся херня, ты будешь как слепой кот, сука, искать, где же косяк. Разные источники — разные сателлиты. Полная трассируемость, и в душе спокойно.
  • Просто по смыслу. Все адресные поля (street, city) — это одна логическая группа. Кидай их в Sat_Customer_Address. Демография (birth_date, gender) — другая. В Sat_Customer_Demographics. Всё аккуратно разложено по полочкам.

Вот смотри, как это выглядело бы в жизни, если бы мы разбирали нашего толстого клиента:

-- Это его скелет, его ID. Больше ничего.
CREATE TABLE Hub_Customer (
    CustomerHashKey CHAR(32) PRIMARY KEY,
    CustomerID VARCHAR(50),
    LoadDate TIMESTAMP,
    RecordSource VARCHAR(20)
);

-- Это одна полочка с мясом: имя, фамилия, почта. Приехало из CRM.
CREATE TABLE Sat_Customer_Core (
    CustomerHashKey CHAR(32),
    LoadDate TIMESTAMP,
    FirstName VARCHAR(100),
    LastName VARCHAR(100),
    Email VARCHAR(255),
    HashDiff CHAR(32),
    PRIMARY KEY (CustomerHashKey, LoadDate)
);

-- А это вторая полочка: адрес. Приехало из другой системы, из службы доставки.
CREATE TABLE Sat_Customer_Address (
    CustomerHashKey CHAR(32),
    LoadDate TIMESTAMP,
    Street VARCHAR(200),
    City VARCHAR(100),
    Country VARCHAR(50),
    HashDiff CHAR(32),
    PRIMARY KEY (CustomerHashKey, LoadDate)
);

И что в сухом остатке? А то, что вместо одной широкой, неповоротливой таблицы у тебя теперь аккуратный конструктор. Нужно добавить новый источник данных с номерами телефонов? Да похуй! Создаёшь новый сателлит Sat_Customer_Phone и подключаешь его к тому же хабу. Старая структура даже не чихнёт. Нужно часто делать отчёты только по адресам? Запрос летает, потому что читает только маленький Sat_Customer_Address, а не всю ту пиздопроебибну простыню, что была раньше.

В общем, суть не в том, чтобы нагородить сложностей, а наоборот — чтобы упростить себе жизнь в долгосрочной перспективе. Как говорится, разделяй и властвуй. Только здесь — разделяй атрибуты и не еби себе мозг.