Действуй как data engineer, который ловил молчаливые drift'ы в продакшене. Спроектируй DQ-стратегию для: {{pipeline}}. Стек: {{stack}}.
Зачем формальные DQ-чеки
Без них баги ловятся через "цифра в отчёте странная". Цикл: аналитик заметил → инженер 3 дня ищет → находит, что неделю назад дубль. Формальные чеки сокращают это до "падение пайплайна → исправили за час".
Типы checks
Schema
Структура данных не уплыла:
- Колонки присутствуют, типы те же
- Новые колонки — warn, удаление существующих — fail
- Constraint'ы (NOT NULL, length) совпадают
Запускать: до transform'а в staging.
Nullness
NOT NULLна ключи, FK, бизнес-критичные поля- % NULL в опциональных полях не должен внезапно вырасти (drift)
SELECT
COUNT(*) FILTER (WHERE user_id IS NULL) AS null_user_id,
COUNT(*) AS total
FROM stg_orders;
-- fail if null_user_id > 0
Uniqueness
PK и сурогаты должны быть уникальны. Особенно после merge'ей — дубли любят появляться там.
SELECT order_key, COUNT(*) FROM fct_orders GROUP BY 1 HAVING COUNT(*) > 1;
Referential integrity
Каждый FK в факте находит свою dim. Иначе in BI получишь NULL'ы и непонятно почему.
SELECT f.customer_key FROM fct_orders f
LEFT JOIN dim_customer d USING (customer_key)
WHERE d.customer_key IS NULL;
Freshness
max(loaded_at) против SLA. Каждый mart знает, как часто должен обновляться.
SELECT EXTRACT(EPOCH FROM (NOW() - MAX(loaded_at)))/3600 AS hours_stale
FROM marts.fct_orders;
-- warn > 2h, fail > 4h
Business rules
То, что не выводится из схемы:
- "сумма выручки w/w не падает > 30%"
- "AOV (avg order value) в коридоре $20-$500"
- "% refunds < 5%"
- "никаких заказов с future ship_date"
Это самые ценные тесты — ловят bug'и, которые schema-валидация пропустит.
Где запускать
| Где | Что проверяем | Действие при fail | | Input (raw) | Schema, freshness источника | Останавливаем pipeline, алерт data team | | Output (mart) | Uniqueness, business rules | Останавливаем downstream, алерт consumers | | Cross-table | Referential, реконсиляция | Алерт, но не блокируем (часто eventual consistency) |
Fail vs warn
| Уровень | Когда | Что делает | | FAIL | Данные сломаны, использовать нельзя | Прерывает pipeline, dashboard "stale", алерт | | WARN | Подозрительно, но не критично | Логирует в метрику, не останавливает | | INFO | Drift-мониторинг | Только в дашборд тренда |
Каждый чек должен иметь явный severity, иначе все становятся "критичны" и alert fatigue.
Дашборд для drift
Метрики, которые стоит трекать как time-series:
- row count per table per day
- % null по бизнес-критичным колонкам
- distinct values в low-cardinality колонках (изменения = новые статусы появились)
- p50/p95 числовых полей (AOV, latency, etc.)
- freshness lag
Алерты на резкие изменения (>3σ от 30-дневной нормы), не на абсолютные значения.
Вывод
## Чек-лист по таблицам
| Таблица | Schema | Nullness | Unique | Ref | Freshness | Business |
## Severity matrix
| Чек | FAIL/WARN | Канал алерта | Owner |
## Бизнес-правила
| Правило | SQL | Severity | Owner |
## Drift-дашборд
| Метрика | Источник | Тренд | Алерт-порог |
Anti-patterns
- ❌ Всё на FAIL — приходит 50 алертов в день, команда выключает уведомления
- ❌ Только schema-тесты — пропускают логические баги ("все суммы умножились на 100")
- ❌ Тесты только в проде — должны бежать в CI на staging, иначе ловишь после релиза
- ❌ Бизнес-правила в одном гигантском SQL — невозможно понять, что именно сломалось
- ❌ Нет owner'а у чека — никто не реагирует на алерт, через неделю все игнорируют
Мониторинг и алёрты
Что мерить, какие алёрты ставить, как не превратить on-call в ад.
Observability: метрики, логи, трейсы
Что и где собирать, как соединять три пилара, какой бюджет на cardinality и хранение.
Дизайн cron jobs: scheduling, overlap, observability
Cron vs scheduler service, что делать с overlap'ами, как избежать missed runs, observability и monitoring, failure handling.