Перейти к содержанию

Data Vault 2.0

Data Vault 2.0 — гибкое хранилище

Data Vault — методология проектирования хранилища данных, предложенная Дэном Линстедтом (Dan Linstedt) в начале 2000-х. Если Star Schema оптимизирована для аналитики, то Data Vault оптимизирована для загрузки и хранения данных из множества источников.

Это не замена Кимбаллу, а другой слой: Data Vault живёт между источниками и витринами. Данные сначала попадают в Data Vault (raw vault), а затем преобразуются в звёздную схему для BI.


Зачем нужен Data Vault

Представь, что у тебя 10 систем-источников: CRM, ERP, сайт, мобильное приложение. Каждая система по-своему описывает клиента, товар, заказ. Проблемы:

  • Конфликты ключей — один и тот же клиент может иметь ID = 42 в CRM и ID = 7891 в ERP
  • Разные схемы — поля не совпадают, форматы дат отличаются
  • Частые изменения — источники меняют структуру, и всё хранилище ломается
  • Аудит — нужно знать, откуда пришла каждая запись и когда

Кулинарная аналогия

Star Schema — это сервировка стола для гостей. Data Vault — это хорошо организованная кладовая, где каждый ингредиент подписан, датирован и можно отследить, от какого поставщика он пришёл.


Три типа таблиц

Data Vault состоит из трёх типов таблиц: Hub, Link и Satellite.

Hub — бизнес-сущность

Hub хранит уникальные бизнес-ключи — идентификаторы сущностей из источников.

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

SQL
CREATE TABLE hub_customer (
    -- хэш бизнес-ключа (MD5/SHA-1 от customer_id + source)
    hub_customer_hk   CHAR(32) PRIMARY KEY,
    -- натуральный бизнес-ключ
    customer_id       VARCHAR(50) NOT NULL,
    -- метаданные загрузки
    load_date         TIMESTAMP NOT NULL DEFAULT NOW(),
    record_source     VARCHAR(100) NOT NULL
);

CREATE TABLE hub_product (
    hub_product_hk    CHAR(32) PRIMARY KEY,
    product_id        VARCHAR(50) NOT NULL,
    load_date         TIMESTAMP NOT NULL DEFAULT NOW(),
    record_source     VARCHAR(100) NOT NULL
);

CREATE TABLE hub_order (
    hub_order_hk      CHAR(32) PRIMARY KEY,
    order_id          VARCHAR(50) NOT NULL,
    load_date         TIMESTAMP NOT NULL DEFAULT NOW(),
    record_source     VARCHAR(100) NOT NULL
);

Зачем хэш-ключ?

Хэш от бизнес-ключа (MD5('CRM|42')) заменяет суррогатный ключ. Его можно вычислить заранее, не обращаясь к базе, что упрощает параллельную загрузку из разных источников.

Link фиксирует отношения между двумя или более хабами.

Правила: - Содержит хэш-ключи связанных хабов + свой хэш-ключ - Одна строка на одну уникальную комбинацию - Не содержит описательных атрибутов

SQL
CREATE TABLE link_order_customer (
    link_order_customer_hk  CHAR(32) PRIMARY KEY,
    hub_order_hk            CHAR(32) NOT NULL REFERENCES hub_order(hub_order_hk),
    hub_customer_hk         CHAR(32) NOT NULL REFERENCES hub_customer(hub_customer_hk),
    load_date               TIMESTAMP NOT NULL DEFAULT NOW(),
    record_source           VARCHAR(100) NOT NULL
);

CREATE TABLE link_order_product (
    link_order_product_hk   CHAR(32) PRIMARY KEY,
    hub_order_hk            CHAR(32) NOT NULL REFERENCES hub_order(hub_order_hk),
    hub_product_hk          CHAR(32) NOT NULL REFERENCES hub_product(hub_product_hk),
    load_date               TIMESTAMP NOT NULL DEFAULT NOW(),
    record_source           VARCHAR(100) NOT NULL
);

Satellite — описательные атрибуты

Satellite хранит контекст (атрибуты) хаба или линка, с полной историей изменений.

Правила: - Привязан к одному хабу или линку через хэш-ключ - Содержит описательные атрибуты + load_date + hash_diff - Каждое изменение атрибутов — новая строка (полная историзация) - hash_diff — хэш от всех атрибутов для быстрого сравнения

SQL
-- Атрибуты клиента
CREATE TABLE sat_customer_details (
    hub_customer_hk   CHAR(32) NOT NULL REFERENCES hub_customer(hub_customer_hk),
    load_date         TIMESTAMP NOT NULL,
    -- хэш от всех атрибутов — для быстрого сравнения «изменилось ли что-то»
    hash_diff         CHAR(32) NOT NULL,
    name              VARCHAR(100),
    email             VARCHAR(200),
    city              VARCHAR(100),
    segment           VARCHAR(50),
    record_source     VARCHAR(100) NOT NULL,
    PRIMARY KEY (hub_customer_hk, load_date)
);

-- Атрибуты товара
CREATE TABLE sat_product_details (
    hub_product_hk    CHAR(32) NOT NULL REFERENCES hub_product(hub_product_hk),
    load_date         TIMESTAMP NOT NULL,
    hash_diff         CHAR(32) NOT NULL,
    name              VARCHAR(200),
    category          VARCHAR(100),
    unit_price        NUMERIC(10,2),
    record_source     VARCHAR(100) NOT NULL,
    PRIMARY KEY (hub_product_hk, load_date)
);

-- Атрибуты связи заказ-товар (количество, цена)
CREATE TABLE sat_order_product (
    link_order_product_hk  CHAR(32) NOT NULL
        REFERENCES link_order_product(link_order_product_hk),
    load_date              TIMESTAMP NOT NULL,
    hash_diff              CHAR(32) NOT NULL,
    quantity               INT,
    unit_price             NUMERIC(10,2),
    total_amount           NUMERIC(12,2),
    record_source          VARCHAR(100) NOT NULL,
    PRIMARY KEY (link_order_product_hk, load_date)
);

Загрузка данных

Загрузка в Data Vault всегда идёт в определённом порядке: сначала хабы, потом линки, потом сателлиты.

SQL
-- 1. Загрузка хаба клиентов
INSERT INTO hub_customer (hub_customer_hk, customer_id, record_source)
SELECT
    MD5('CRM|' || customer_id::TEXT),
    customer_id::TEXT,
    'CRM'
FROM source_customers s
WHERE NOT EXISTS (
    SELECT 1 FROM hub_customer h
    WHERE h.hub_customer_hk = MD5('CRM|' || s.customer_id::TEXT)
);

-- 2. Загрузка сателлита (только если данные изменились)
INSERT INTO sat_customer_details
    (hub_customer_hk, load_date, hash_diff, name, email, city, segment, record_source)
SELECT
    MD5('CRM|' || s.customer_id::TEXT),
    NOW(),
    MD5(s.name || '|' || s.email || '|' || COALESCE(s.city, '')),
    s.name,
    s.email,
    s.city,
    s.segment,
    'CRM'
FROM source_customers s
WHERE NOT EXISTS (
    SELECT 1 FROM sat_customer_details sat
    WHERE sat.hub_customer_hk = MD5('CRM|' || s.customer_id::TEXT)
      AND sat.hash_diff = MD5(s.name || '|' || s.email || '|' || COALESCE(s.city, ''))
);

Идемпотентность

Загрузка в Data Vault идемпотентна: повторный запуск с теми же данными не создаст дубликатов. Хабы проверяют уникальность по хэш-ключу, сателлиты — по hash_diff.


Получение данных: Point-in-Time и Bridge

Запросы напрямую к Data Vault громоздки. Для аналитики строят витрины (Star Schema) поверх Data Vault. Но если нужно получить данные на конкретный момент:

Актуальное состояние клиента

SQL
-- Последняя версия атрибутов каждого клиента
SELECT
    h.customer_id,
    s.name,
    s.email,
    s.city,
    s.segment
FROM hub_customer h
JOIN sat_customer_details s ON h.hub_customer_hk = s.hub_customer_hk
WHERE s.load_date = (
    SELECT MAX(load_date)
    FROM sat_customer_details
    WHERE hub_customer_hk = h.hub_customer_hk
);

Состояние на конкретную дату

SQL
-- Атрибуты клиента на 15 января 2026
SELECT
    h.customer_id,
    s.name,
    s.email,
    s.segment
FROM hub_customer h
JOIN sat_customer_details s ON h.hub_customer_hk = s.hub_customer_hk
WHERE s.load_date = (
    SELECT MAX(load_date)
    FROM sat_customer_details
    WHERE hub_customer_hk = h.hub_customer_hk
      AND load_date <= '2026-01-15'
);

Data Vault vs Star Schema

Критерий Star Schema Data Vault
Назначение Аналитика, BI Интеграция и хранение
Оптимизирована для Чтения (SELECT) Загрузки (INSERT)
Историзация Через SCD Встроена (сателлиты)
Добавление источника Может потребовать перестройки Добавить хаб/линк/сателлит
Аудит Ограничен Полный (record_source, load_date)
Сложность запросов Простые (fact + dim) Сложные (hub + link + sat)
Когда применять Витрины для BI Промежуточный слой хранилища

Типичная архитектура

На практике Data Vault и Star Schema не конкурируют, а дополняют друг друга:

Источники → Staging → Data Vault (Raw Vault) → Business Vault → Star Schema (витрины) → BI


Что запомнить

  • Data Vault состоит из трёх типов таблиц: Hub (ключи), Link (связи), Satellite (атрибуты)
  • Хэш-ключи вместо суррогатных — упрощают параллельную загрузку
  • Полная историзация встроена в сателлиты через load_date
  • Аудит «из коробки» — каждая запись знает, откуда пришла и когда
  • Data Vault — не замена Star Schema, а промежуточный слой между источниками и витринами
  • Подходит, когда много источников, частые изменения схем, нужен полный аудит