Прямой ответ
Проверки качества данных в конвейере выполняются между этапами обработки, поэтому некорректные данные не попадают к потребителю. Каждая проверка относится к одному из четырёх классов.
| Класс проверки | Что проверяется | Пример нарушения |
|---|---|---|
| Обязательность | Наличие значения в ключевых полях | Пустой идентификатор клиента |
| Уникальность | Отсутствие дубликатов по ключу | Две строки с одним идентификатором |
| Согласованность | Соответствие связанных данных | Заказ без существующего клиента |
| Актуальность | Своевременность поступления | Данные за вчера отсутствуют |
-- Обязательность и допустимость значения
ALTER TABLE dwh.orders
ALTER COLUMN customer_id SET NOT NULL,
ADD CONSTRAINT chk_amount_positive CHECK (amount_minor > 0);
-- Уникальность ключа
CREATE UNIQUE INDEX IF NOT EXISTS uq_orders_id ON dwh.orders (order_id);
Ограничения на уровне таблицы обеспечивают обязательность и уникальность независимо от способа записи. Ограничение не покрывает согласованность между таблицами и актуальность поступления, поэтому эти классы проверяются отдельно.
Оценка распределения значений перед проектированием проверок выполняется профилированием; о нём — в статье про профилирование данных.
Реакция на нарушение проверки и стоимость контроля
Проверка без определённой реакции не изменяет поведение конвейера, поэтому для каждой проверки задаётся действие при нарушении.
Блокирующая проверка. Нарушение останавливает обработку, и данные не передаются дальше. Применяется для ключевых полей, где некорректное значение делает результат непригодным.
Предупреждающая проверка. Нарушение фиксируется в журнале, обработка продолжается. Применяется для полей, где отклонение допустимо в малой доле.
Карантин. Нарушающие строки перемещаются в отдельное хранилище, обработка остальных продолжается. Применяется, когда доля нарушений невелика, а потеря всех данных недопустима.
Практическое следствие: выбор реакции определяется долей допустимых отклонений и стоимостью ошибки в результате.
Стоимость проверки влияет на размещение в конвейере. Проверка уникальности по всей таблице требует чтения всего объёма, поэтому выполняется реже либо по инкрементальной части. Проверка обязательности по поступающей порции выполняется быстро и размещается на входе.
Отдельный аспект — порог для предупреждающих проверок. Доля отклонений задаётся явно, иначе проверка срабатывает на каждом запуске и перестаёт восприниматься. О построении порогов по наблюдаемым значениям — в статье про пороги оповещений.
Размещение проверок между этапами конвейера описано в статье про ETL-конвейер; сверка наборов данных после изменения выполняется по методике из статьи про проверку данных после миграции.
Размещение проверок в конвейере
Место проверки определяет, какие данные она охватывает и какова стоимость её выполнения.
Проверка на входе выполняется по поступающей порции, поэтому обнаруживает нарушение до записи в хранилище. Стоимость низкая, поскольку объём порции ограничен.
Проверка после преобразования выполняется по результату, поэтому охватывает ошибки преобразования, а не только исходных данных. Стоимость выше, поскольку проверяется весь результат.
Проверка перед выдачей потребителю выполняется по витрине, поэтому обнаруживает расхождение на последнем этапе. Стоимость зависит от объёма витрины.
Практическое следствие: проверка размещается там, где нарушение обнаруживается раньше, а стоимость выполнения ниже. Дублирование одной проверки на нескольких этапах увеличивает стоимость без выигрыша.
Практика: внедрение проверок в конвейер
1. Начните с обязательности ключевых полей. Пустое значение в идентификаторе делает строку непригодной для соединения и агрегации.
2. Обеспечьте уникальность ключа на уровне таблицы. Ограничение работает независимо от способа записи, поэтому покрывает и ручные операции.
3. Проверяйте согласованность связанных данных. Заказ без существующего клиента указывает на расхождение источников.
4. Контролируйте актуальность поступления. Отсутствие данных за ожидаемый период означает сбой загрузки, а не отсутствие событий.
5. Задайте реакцию для каждой проверки. Блокировка, предупреждение либо карантин выбирается по стоимости ошибки.
6. Установите пороги для предупреждающих проверок. Доля допустимых отклонений задаётся явно, иначе проверка срабатывает постоянно.
7. Логируйте результаты проверок. История нарушений показывает, является ли отклонение разовым либо систематическим.
Рекомендации:
- Различайте обязательные и желательные свойства. Блокировка на желательном свойстве останавливает конвейер из-за допустимого отклонения.
- Учитывайте стоимость проверки. Проверка по всему объёму выполняется реже, чем проверка поступающей порции.
- Не дублируйте проверки на нескольких уровнях. Ограничение на таблице и проверка в конвейере на одно свойство избыточны.
- Проверяйте причину нарушения, а не только факт. Систематическое нарушение указывает на изменение в источнике, а не на случайность.
- Пересматривайте проверки после изменения источника. Изменение схемы источника делает проверку непригодной либо пропускает новое нарушение.
Практический сценарий: отчёт содержал заказы без клиента
Контекст: в отчёте появились строки с пустым значением клиента, сумма по региону оказалась недостоверной.
- Диагностика. Проверка уникальности и актуальности выполнялась, проверка обязательности поля клиента отсутствовала. Строки с пустым значением проходили обработку и попадали в агрегат.
- Причина. Источник допускал создание заказа без указания клиента в определённом сценарии, и это не было учтено при проектировании проверок. Обязательность поля не была зафиксирована ограничением на таблице.
- Действия. (а) Добавили ограничение обязательности на поле клиента в интегрированном слое; (б) настроили карантин для строк, нарушающих обязательность, чтобы остальная часть загрузки продолжалась; (в) добавили предупреждающую проверку доли строк в карантине с порогом; (г) согласовали с источником обязательность поля в сценарии создания заказа; (д) пересчитали отчёт за период с исключением строк из карантина.
- Результат. Строки без клиента не попадают в агрегат, а доля нарушений контролируется порогом.
Вывод: отсутствие проверки обязательности ключевого поля пропускает некорректные данные в результат. Ограничение на таблице в сочетании с карантином сохраняет обработку остальной части данных.
FAQ
Какие проверки выполняются на уровне таблицы, а какие в конвейере? Обязательность и уникальность обеспечиваются ограничениями таблицы. Согласованность между таблицами и актуальность поступления проверяются в конвейере.
Что делать со строками, нарушающими проверку? Перемещать в карантин, если доля нарушений невелика и потеря всех данных недопустима. Блокировать обработку, если некорректные данные делают результат непригодным.
Нужен ли порог для предупреждающих проверок? Да, иначе проверка срабатывает на каждом запуске и перестаёт восприниматься. Доля допустимых отклонений задаётся явно.
Как проверить актуальность данных? Сравнением максимального значения даты в данных с ожидаемым периодом. Отсутствие данных за ожидаемый период означает сбой загрузки.
Источники: PostgreSQL constraints, CREATE INDEX, dbt — ссылки в шапке.