Инженерия данных
Архитектуры хранения, ETL против ELT, слои данных и захват изменений (CDC).
16 вопросов
JuniorТеорияОчень частоПочему OLTP-система нормализует таблицы, а аналитическое хранилище их денормализует?
Почему OLTP-система нормализует таблицы, а аналитическое хранилище их денормализует?
OLTP нормализует, убирая избыточность, чтобы записи были консистентны и дёшевы — факт живёт в одном месте. Аналитика денормализует ради чтения: предварительные JOIN и дублирование контекста убирают дорогие JOIN при запросе, меняя простоту записи на быстрые чтения.
Типичные ошибки
- ✗Путать, какая нагрузка нормализует, а какая денормализует
- ✗Утверждать, что дублировать столбец в таблицу хранилища запрещено
- ✗Говорить, что денормализация про диск, а не про уход от JOIN
Уточняющие вопросы
- →Какие аномалии записи предотвращает нормализация в OLTP?
- →Какова цена денормализации, когда атрибут измерения меняется?
JuniorТеорияОчень частоЧем в star schema fact-таблица отличается от dimension-таблицы и почему её предпочитают OLTP?
Чем в star schema fact-таблица отличается от dimension-таблицы и почему её предпочитают OLTP?
Fact-таблица хранит события — одна строка на транзакцию, с числовыми мерами и внешними ключами. Dimension-таблицы хранят контекст — клиент, продукт, дата. Star предпочитают за немногие денормализованные JOIN, простые и быстрые для агрегации.
Типичные ошибки
- ✗Путать, какая таблица хранит меры, а какая описательный контекст
- ✗Считать star просто переименованной полностью нормализованной OLTP-схемой
- ✗Верить, что аналитики любят её за хранение, а не за простые JOIN
Уточняющие вопросы
- →Почему широкое денормализованное измерение ускоряет аналитические запросы?
- →Что такое гранулярность fact-таблицы и почему она важна?
JuniorТеорияОчень частоВ чём разница между Data Warehouse, Data Lake и Lakehouse?
В чём разница между Data Warehouse, Data Lake и Lakehouse?
Data Warehouse хранит структурированные, выверенные данные по схеме-при-записи — смоделированные и готовые к BI. Data Lake дёшево хранит сырые данные любого формата по схеме-при-чтении, накладывая структуру только при запросе.
Типичные ошибки
- ✗Менять местами схему-при-записи и схему-при-чтении у склада и озера
- ✗Считать lakehouse просто меньшим складом
- ✗Забывать, что lakehouse добавляет ACID/табличную семантику над озером
Уточняющие вопросы
- →Когда схема-при-чтении озера станет недостатком?
- →Какую проблему Delta или Iceberg решают над обычными файлами озера?
JuniorТеорияЧастоЧто делает analytics engineer из того, что не делают ни data engineer, ни аналитик?
Что делает analytics engineer из того, что не делают ни data engineer, ни аналитик?
Analytics engineer владеет слоем трансформаций — превращает сырые таблицы в чистые, тестированные, документированные модели (staging к marts), обычно в dbt. Data engineer приземляет сырые данные; аналитик потребляет marts. Engineer соединяет их.
Типичные ошибки
- ✗Путать analytics engineer с чистым строителем дашбордов
- ✗Считать три роли взаимозаменяемыми без отдельного слоя
- ✗Отдавать моделирование marts data engineer'у
Уточняющие вопросы
- →Почему роль analytics engineer появилась с облачными хранилищами и dbt?
- →Как тесты и документация в слое моделей помогают аналитикам ниже?
JuniorТеорияЧастоЧто реально заставляет конвейер стримить, а не батчить, и почему «реальное время» чаще хотят, чем нуждаются?
Что реально заставляет конвейер стримить, а не батчить, и почему «реальное время» чаще хотят, чем нуждаются?
Стримить нужно, только когда решение действует за секунды — блокировка фрода, живые алерты, персонализация. Иначе batch проще, дешевле и легче для backfill. Дашборды смотрят раз в час или в день, поэтому «реальное время» — предпочтение, а не требование.
Типичные ошибки
- ✗Выбирать стриминг по объёму данных, а не по задержке решения
- ✗Считать, что стриминг всегда дешевле и проще batch
- ✗Принимать любую просьбу о «реальном времени» за жёсткое требование
Уточняющие вопросы
- →Какие вопросы вскрывают, нужна ли стейкхолдеру задержка меньше минуты?
- →Почему batch-конвейер обычно легче для backfill и переобработки?
JuniorТеорияЧастоЧем жертвуешь, выбирая star schema против snowflake против one big table?
Чем жертвуешь, выбирая star schema против snowflake против one big table?
Star держит денормализованные измерения — мало JOIN, немного избыточности. Snowflake нормализует их в под-таблицы — меньше избыточности, больше JOIN. OBT плоско соединяет всё — ноль JOIN и быстрое чтение, но максимум дублирования и сложность поддержки.
Типичные ошибки
- ✗Путать, что из star и snowflake является нормализованным
- ✗Утверждать, что у one big table меньше всего дублирования
- ✗Верить, что три формы имеют одинаковую стоимость чтения
Уточняющие вопросы
- →Когда лишняя нормализация snowflake реально стоит этих JOIN?
- →Какие проблемы поддержки возникают, когда меняется атрибут источника в one big table?
MiddleТеорияЧастоЧто содержит data contract и что значит «нарушить его» для команды-производителя?
Что содержит data contract и что значит «нарушить его» для команды-производителя?
Data contract — гарантия производителя про датасет: схема, типы, семантика, freshness/SLA, допустимые значения. Нарушить его — несовместимое изменение (rename столбца, смена типа или смысла) без версии и предупреждения, потребители тихо ломаются.
Типичные ошибки
- ✗Сводить data contract к юридическому или биллинговому документу
- ✗Возлагать обязанность стабильности на потребителя, а не производителя
- ✗Считать смену типа или смысла безопасно обратно совместимой
Уточняющие вопросы
- →Как версионирование даёт производителю менять схему, не ломая потребителей?
- →Какое изменение контракта — нарушение, даже если имя столбца не менялось?
MiddleТеорияЧастоВ чём разница между ETL и ELT и когда что подходит?
В чём разница между ETL и ELT и когда что подходит?
ETL преобразует данные до загрузки в приёмник — чистит и переформирует на отдельном движке, затем пишет выверенный результат. ELT сначала грузит сырые данные в хранилище и преобразует их там, опираясь на дешёвый масштабируемый MPP-движок хранилища.
Типичные ошибки
- ✗Путать, какой из них преобразует до, а какой после загрузки
- ✗Называть ELT устаревшим подходом, тогда как он современный
- ✗Игнорировать, что ELT опирается на вычисления самого хранилища
Уточняющие вопросы
- →Почему дешёвые вычисления хранилища делают ELT привлекательным?
- →Когда преобразование до загрузки (ETL) обязательно?
MiddleДизайнЧастоЕжедневная задача агрегирует вчерашние заказы в mart revenue_daily, добавляя результат через INSERT. Иногда оркестратор перезапускает задачу после временного сбоя, и в такие дни выручка за эту дату выходит удвоенной. Нужно сделать конвейер идемпотентным — повторный запуск за дату должен оставить mart ровно в том же состоянии, что и один запуск, без двойного счёта и ручной чистки. Какой дизайн этого добивается?
Ежедневная задача агрегирует вчерашние заказы в mart revenue_daily, добавляя результат через INSERT. Иногда оркестратор перезапускает задачу после временного сбоя, и в такие дни выручка за эту дату выходит удвоенной. Нужно сделать конвейер идемпотентным — повторный запуск за дату должен оставить mart ровно в том же состоянии, что и один запуск, без двойного счёта и ручной чистки. Какой дизайн этого добивается?
Сделать запись идемпотентной по ключу-партиции — delete-then-insert (или MERGE) строк целевой даты каждый запуск, чтобы повтор заменял эту дату, а не дописывал. Вывод за дату становится чистой функцией входа, стабильной сколько бы раз ни запускали.
Типичные ошибки
- ✗Дедуплицировать агрегированный mart вместо замены партиции даты
- ✗Верить, что один lock делает append-only INSERT идемпотентным
- ✗Чинить удвоение лишь при чтении в нижестоящих запросах
Уточняющие вопросы
- →Почему ключ записи на партицию даты делает перезапуски безопасными?
- →Как INSERT OVERWRITE или MERGE выражают ту же идемпотентную замену?
MiddleДизайнЧастоКаждое утро вчерашнее число выручки на дашборде меняется, потому что события за день продолжают приходить день-два после (мобильные клиенты синкают поздно, апстрим делает backfill). Стейкхолдеры думают, что дашборд врёт. Спроектируйте, как конвейеру обрабатывать эти поздно приходящие данные, чтобы числа перестали тихо сдвигаться под людьми.
Каждое утро вчерашнее число выручки на дашборде меняется, потому что события за день продолжают приходить день-два после (мобильные клиенты синкают поздно, апстрим делает backfill). Стейкхолдеры думают, что дашборд врёт. Спроектируйте, как конвейеру обрабатывать эти поздно приходящие данные, чтобы числа перестали тихо сдвигаться под людьми.
Переобрабатывать скользящее окно оглядки (например 3 дня) каждый запуск, чтобы поздние события попали в свою партицию по event-date, и помечать недавние даты предварительными. Число меняется, но метка «as of» показывает, что это ожидаемо, а не поломка.
Типичные ошибки
- ✗Выбрасывать поздние события вместо переобработки в их дату
- ✗Штамповать события временем обработки и путать дату
- ✗Принимать ожидаемый дрейф поздних данных за баг, который надо заморозить
Уточняющие вопросы
- →Насколько широким должно быть окно оглядки и что задаёт эту границу?
- →Почему помечать недавние даты предварительными, а не прятать изменение?
SeniorТеорияЧастоКакими слоями данных вы оперируете в платформе и зачем они нужны?
Какими слоями данных вы оперируете в платформе и зачем они нужны?
Типичное medallion-слоение: raw/staging (точная приземлённая копия источника), затем нормализованный/очищенный слой (дедуплицированный, типизированный, согласованный), затем витрины данных (выверенные, агрегированные, для бизнеса).
Типичные ошибки
- ✗Разворачивать порядок raw → очищенный → витрины
- ✗Утверждать, что слои лишь тратят место без пользы
- ✗Делать всю очистку внутри запросов потребителей, а не в слое
Уточняющие вопросы
- →Зачем держать точную сырую копию, не показываемую BI?
- →Как слоение помогает при изменении схемы источника?
MiddleДизайнИногдаВы добавляете тесты качества данных на revenue mart. Кандидаты: not-null, unique (первичный ключ), accepted values (enum вроде статуса заказа), referential integrity (клиент каждого заказа существует), freshness (данные пришли вовремя) и volume anomaly (число строк в границах). Какой один тест обычно ловит больше всего реальных багов в проде и почему?
Вы добавляете тесты качества данных на revenue mart. Кандидаты: not-null, unique (первичный ключ), accepted values (enum вроде статуса заказа), referential integrity (клиент каждого заказа существует), freshness (данные пришли вовремя) и volume anomaly (число строк в границах). Какой один тест обычно ловит больше всего реальных багов в проде и почему?
Больше всего ловит тест uniqueness / первичного ключа: сломанный JOIN или перезапуск размножает строки и тихо удваивает выручку, чего не заметят ни not-null, ни проверка диапазона. Дубль ключа — самая частая причина неверных итогов в mart.
Типичные ошибки
- ✗Считать, что суммы SQL игнорируют дубли строк от fan-out JOIN
- ✗Ставить not-null выше теста uniqueness для верности итогов
- ✗Считать, что каждая проверка ловит равную долю багов
Уточняющие вопросы
- →Как many-to-many fan-out JOIN завышает суммируемую меру?
- →Почему freshness — вторая по ценности проверка на дневном mart?
MiddleДебаггингИногдаЕжедневная задача перезапустилась после ретрая, и выручка за дату удвоилась — найдите дефект дизайна, а не плохую строку
Ежедневная задача перезапустилась после ретрая, и выручка за дату удвоилась — найдите дефект дизайна, а не плохую строку
Загрузка append-only — второй INSERT за тот же :run_date задваивает дату. Сделать идемпотентной, заменяя дату каждый запуск: DELETE строк :run_date, затем INSERT, или MERGE — чтобы повтор перезаписывал, а не дописывал.
Типичные ошибки
- ✗Винить плохую строку, а не сам append-only дизайн загрузки
- ✗Гасить удвоение через AVG вместо замены даты
- ✗Дедуплицировать при чтении вместо идемпотентной записи
Уточняющие вопросы
- →Почему DELETE-затем-INSERT партиции даты делает загрузку идемпотентной?
- →Как unique-ограничение на order_date вскрыло бы этот баг раньше?
MiddleТеорияИногдаКлиент переехал в другой город. Что при SCD (медленно меняющееся измерение) Type 1 против Type 2 будет с прошлогодним отчётом?
Клиент переехал в другой город. Что при SCD (медленно меняющееся измерение) Type 1 против Type 2 будет с прошлогодним отчётом?
Type 1 перезаписывает город на месте, поэтому вся история — включая прошлогодний отчёт — показывает новый город, старое значение теряется. Type 2 добавляет датированную строку измерения, прошлогодний отчёт держит старый город, новый действует дальше.
Типичные ошибки
- ✗Путать, какой тип перезаписывает, а какой версионирует историю
- ✗Считать, что оба типа одинаково влияют на исторические отчёты
- ✗Верить, что Type 2 удаляет или задваивает клиента вместо версионирования
Уточняющие вопросы
- →Как строка Type 2 отмечает, какая версия действовала на конкретную дату?
- →Когда потеря истории (Type 1) — действительно верный выбор?
SeniorТеорияРедкоЧто такое Change Data Capture (CDC) и как его реализовать (Pull против Push)?
Что такое Change Data Capture (CDC) и как его реализовать (Pull против Push)?
CDC захватывает построчные изменения (insert, update, delete) из источника, чтобы нижестоящие системы оставались синхронными без полных перезагрузок. Log-based CDC читает журнал транзакций БД (WAL/binlog, например Debezium) и стримит изменения — push-модель с низким лагом.
Типичные ошибки
- ✗Приравнивать CDC к полной перезагрузке таблицы
- ✗Путать, какой из pull/push является log-based и низколаговым
- ✗Забывать, что log-based CDC читает журнал транзакций БД
Уточняющие вопросы
- →Почему log-based CDC нагружает источник меньше, чем опрос?
- →Как CDC обрабатывает удаления, которые опрос может пропустить?
SeniorДизайнРедкоАпстрим-команда переименовала столбец без предупреждения, и за ночь сломались 30 дашбордов ниже. Руководство просит спроектировать процесс и тесты, делающие такой класс сбоев невозможным, — не чинить 30 дашбордов. Какое сочетание контракта, версионирования и автопроверок вы внедрите, чтобы несовместимое изменение схемы апстрима ловилось до попадания в прод?
Апстрим-команда переименовала столбец без предупреждения, и за ночь сломались 30 дашбордов ниже. Руководство просит спроектировать процесс и тесты, делающие такой класс сбоев невозможным, — не чинить 30 дашбордов. Какое сочетание контракта, версионирования и автопроверок вы внедрите, чтобы несовместимое изменение схемы апстрима ловилось до попадания в прод?
Наложить data contract на источник со schema-тестами в CI производителя, чтобы переименование ломало их сборку, а не наши дашборды. Ломающие изменения выходят версионно с окном депрекации, а schema-diff проверка блокирует деплой — сбой сдвигается влево, к производителю.
Типичные ошибки
- ✗Чинить реактивно после релиза, а не сдвигать проверку влево
- ✗Замораживать схему навсегда вместо версионирования изменений
- ✗Закалять 30 потребителей вместо контракта с производителем
Уточняющие вопросы
- →Почему schema-тест должен идти в CI производителя, а не только в вашем?
- →Как окно депрекации даёт потребителям мигрировать до переименования?