Вопросы на собеседовании: Дата-инженер
100 реальных вопросов с образцовыми ответами и пояснениями для уровня Junior.
Смотреть пример резюме: Дата-инженер →Тренировка флешкарточками
Интервальное повторение · Hunter Pass
Вопросы
У SELECT порядок записи отличается от логического порядка вычисления.
- Части запроса записывают так: SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY и LIMIT.
- Логическое вычисление начинается с FROM и соединений, после чего выполняются WHERE, GROUP BY, HAVING, SELECT, ORDER BY и LIMIT.
- Поскольку WHERE выполняется до SELECT и агрегации, псевдоним из SELECT обычно нельзя использовать в WHERE, а результаты агрегатов нужно фильтровать через HAVING, а не WHERE.
Зачем это спрашивают: Следствие про невидимый в WHERE алиас показывает, что кандидат понимает порядок вычисления, а не только синтаксис.
WHERE и HAVING фильтруют данные на разных этапах запроса с группировкой.
- WHERE отбирает отдельные строки до группировки, например оставляет только строки с country = 'DE'.
- HAVING отбирает группы после агрегации, например оставляет группы с SUM(amount) > 1000.
- Условие, которое можно применить в WHERE, обычно стоит размещать именно там, поскольку сокращение числа строк до агрегации уменьшает объём работы.
Зачем это спрашивают: Пункт о производительности ранней фильтрации добавляет инженерный угол, которого интервьюеры ждут от этой классики.
Выбор соединения зависит от того, какие строки без пары должны остаться в результате.
- INNER JOIN оставляет только строки с совпадением в обеих таблицах, поэтому подходит для записей, которые обязаны присутствовать с двух сторон.
- LEFT JOIN сохраняет все строки левой таблицы и заполняет правые колонки значением NULL при отсутствии пары, поэтому подходит для полного списка клиентов с заказами и без них.
- FULL JOIN сохраняет несовпавшие строки с обеих сторон, что удобно при сверке источника и приёмника.
Зачем это спрашивают: Привязка FULL JOIN к сверкам показывает взгляд дата-инженера, а не учебниковые определения.
Соединение размножает строки, когда его ключ не уникален в одной или обеих таблицах.
- Каждая совпавшая пара создаёт строку результата, поэтому связь один-ко-многим или многие-ко-многим может незаметно раздуть количество строк и итоговые суммы.
- До соединения нужно сравнить COUNT с COUNT(DISTINCT key) или выполнить аналогичную проверку уникальности на стороне, где она ожидается.
- После соединения нужно сверить число строк с ожидаемым типом связи и автоматизировать проверки уникальности и количества, чтобы пайплайн остановился до публикации задвоенных данных.
Зачем это спрашивают: Превращение ручной проверки в автоматический тест пайплайна - инженерная привычка, поднимающая ответ.
GROUP BY задаёт детализацию результата, а агрегатные функции вычисляют значение для каждой группы.
- Строки с одинаковыми значениями в перечисленных колонках группировки образуют одну группу результата.
- SUM, COUNT, AVG, MIN и MAX вычисляют отдельное значение для каждой группы.
- Каждая выбранная колонка обычно должна либо входить в GROUP BY, либо находиться внутри агрегатной функции, поэтому колонки группировки должны соответствовать нужной детализации отчёта.
Зачем это спрашивают: Рамка GROUP BY как выбора гранулярности связывает синтаксис с тем, как дата-инженеры реально думают.
Варианты COUNT и другие агрегатные функции по-разному обрабатывают NULL.
- COUNT(*) считает все строки, а COUNT(column) только строки, где значение этой колонки не является NULL.
- SUM, AVG, MIN и MAX пропускают NULL, поэтому AVG учитывает только заполненные значения и может описывать не ту совокупность, которую ожидали.
- COALESCE(column, 0) следует применять лишь тогда, когда пропуск действительно означает ноль, а перед агрегацией стоит проверить долю NULL.
Зачем это спрашивают: Эффект изменённого знаменателя из-за пропущенных NULL - ловушка, ради которой задают этот вопрос.
COUNT(DISTINCT column) считает уникальные значения без NULL, а не строки.
- COUNT(DISTINCT customer_id) позволяет отличить число уникальных клиентов от числа заказов.
- NULL не учитывается, а точный подсчёт уникальных значений на очень больших таблицах может быть дорогим, поэтому для оценки иногда подходит приближённая функция.
- После соединения размножение строк может не изменить число уникальных значений и скрыть ошибку, поэтому нужно также проверять количество строк и связи между ключами.
Зачем это спрашивают: Знание, что размножение строк прячется за неизменными distinct-счётчиками, показывает реальный опыт отладки.
Подзапросы и CTE создают промежуточные результаты, поэтому выбор прежде всего зависит от читаемости и структуры.
- Короткий подзапрос в WHERE или FROM удобен для одной локальной задачи, например для сравнения значения со средним.
- CTE, объявленный через WITH, даёт каждому этапу имя и позволяет читать многошаговое преобразование сверху вниз.
- CTE часто используют в моделях dbt и аналитическом SQL, поскольку именованные этапы проще проверять и при необходимости можно использовать повторно.
Зачем это спрашивают: Дефолт на CTE для многошаговой логики отражает то, как продакшен-SQL реально пишется и ревьюится.
Оконная функция выполняет расчёт по связанным строкам, не схлопывая исходные строки.
- Каждая входная строка остаётся в результате и получает дополнительное вычисленное значение.
- PARTITION BY задаёт связанную группу, а ORDER BY внутри OVER определяет порядок, например в ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at).
- GROUP BY возвращает одну строку на группу, а оконные функции могут показать ранг, предыдущее или накопленное значение для каждой строки внутри группы.
Зачем это спрашивают: Различие строки-выживают - концептуальное ядро, отделяющее понимание от заученного синтаксиса.
Нарастающий итог дневной выручки сочетает агрегацию по дням с оконной суммой.
- Один из вариантов: SELECT order_date, SUM(amount) AS daily_revenue, SUM(SUM(amount)) OVER (ORDER BY order_date) AS running_total FROM orders GROUP BY order_date ORDER BY order_date.
- Внутренний SUM считает выручку за день, а внешний оконный SUM накапливает дневные значения от первой даты до текущей.
- Если добавить в окно PARTITION BY region, итог начнётся заново для каждого региона, при этом region также нужно включить в дневную группировку.
Зачем это спрашивают: Конструкция агрегат-внутри-окна и follow-up про PARTITION BY - ровно то, что проверяет эта классика.
Обычный способ дедупликации ранжирует строки по свежести внутри бизнес-ключа и оставляет первую.
- Можно создать CTE: WITH ranked AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY updated_at DESC) AS rn FROM customers_raw).
- Затем нужно выбрать из CTE строки с WHERE rn = 1 и добавить в ORDER BY стабильный дополнительный критерий, если время у двух записей может совпасть.
- В отличие от DISTINCT, этот способ удаляет повторы по выбранному бизнес-ключу и явно определяет, какая запись победит.
Зачем это спрашивают: Этот паттерн - хлеб ingest-работы, и беглость с ним - сильный джуновский сигнал.
UNION удаляет одинаковые строки результата, а UNION ALL объединяет результаты, сохраняя все строки.
- Удаление дублей требует дополнительной работы, поэтому UNION обычно медленнее UNION ALL.
- В пайплайнах обычно стоит выбирать UNION ALL, если входные наборы не пересекаются или повторы имеют смысл.
- Если нежелательные дубли возможны, явное правило по бизнес-ключу понятнее и безопаснее, чем неявная дедупликация целых строк через UNION.
Зачем это спрашивают: Предпочтение явной ключевой дедупликации молчаливому поведению UNION отражает мышление о качестве пайплайнов.
Условная агрегация помещает CASE WHEN внутрь агрегатной функции и считает метрики по сегментам в одном запросе.
- SUM(CASE WHEN status = 'paid' THEN amount ELSE 0 END) AS paid_revenue суммирует только оплаченные суммы.
- COUNT(CASE WHEN channel = 'mobile' THEN 1 END) AS mobile_orders считает строки, в которых условие возвращает значение, отличное от NULL.
- Несколько таких выражений позволяют рассчитать разные сегменты отчёта за одно чтение таблицы вместо отдельных запросов с фильтрами.
Зачем это спрашивают: Сегментированные метрики за один проход через условную агрегацию - ключевая отчётная техника, которую проверяют.
NULL обозначает неизвестное значение, поэтому для него нужны специальные операторы и функции SQL.
- Сравнения column = NULL и NULL = NULL дают UNKNOWN, а не TRUE, поэтому нужно использовать IS NULL или IS NOT NULL.
- NOT IN может не вернуть ни одной строки, если его подзапрос содержит NULL, поэтому для исключающего соединения часто безопаснее NOT EXISTS.
- COALESCE подставляет явно заданное запасное значение, а NULLIF может заменить нулевой делитель на NULL и предотвратить ошибку деления на ноль.
Зачем это спрашивают: Ловушка NOT IN с NULL отличает тех, кто уже потерял на ней часы, от тех, кому предстоит.
События по месяцам нужно группировать по дате начала месяца с учётом года и нужного часового пояса.
- Типичный запрос вычисляет DATE_TRUNC('month', created_at) AS month, группирует по этому значению и сортирует по нему.
- Группировка только по номеру месяца объединит одинаковые месяцы разных лет, а текстовая подпись месяца может нарушить хронологическую сортировку.
- При необходимости время нужно перевести в бизнес-часовой пояс перед применением DATE_TRUNC, поскольку UTC и местное время могут отнести пограничное событие к разным месяцам.
Зачем это спрашивают: Оговорки про границу года и часовой пояс превращают тривиальный вопрос в проверку продакшен-осознанности.
Последнюю запись для каждой сущности обычно выбирают с помощью оконной функции ROW_NUMBER.
- В CTE или подзапросе нужно вычислить ROW_NUMBER() OVER (PARTITION BY entity_id ORDER BY event_time DESC), а снаружи оставить rn = 1.
- В ORDER BY стоит добавить стабильный дополнительный критерий, чтобы при одинаковом времени двух событий победитель выбирался однозначно.
- Соединение с MAX(event_time) тоже возможно, но без отдельной обработки совпадений оно может вернуть несколько строк для одной сущности.
Зачем это спрашивают: Упоминание обработки ничьих и детерминизма показывает разницу между работающим запросом и корректным.
Основные строковые функции SQL помогают привести грязный текст к единому виду до сравнения, соединения или публикации.
- TRIM убирает пробелы по краям, а LOWER и UPPER выравнивают регистр букв.
- REPLACE удаляет или заменяет нежелательные символы, а SUBSTRING вместе с POSITION либо SPLIT_PART извлекает части составного значения.
- Например, email можно один раз нормализовать при загрузке через LOWER(TRIM(email)), а не повторять ту же очистку во всех последующих запросах.
Зачем это спрашивают: Нормализуй-один-раз-на-инжесте - архитектурный инстинкт, отделяющий инженеров от писателей запросов.
Перед публикацией датасет нужно сверить с надёжными источниками, ожиданиями от преобразований и отдельными примерами записей.
- Итоги следует сравнить с системой-источником или проверенным отчётом, а число строк контролировать на каждом шаге, чтобы найти место неожиданной потери или раздувания данных.
- Отдельно нужно проверить крайние случаи, например NULL в ключах, дубликаты и границы дат.
- Две-три записи стоит вручную проследить от источника до результата, а подозрительно хорошие или плохие показатели исследовать, а не считать правильными по умолчанию.
Зачем это спрашивают: Пошаговая проверка числа строк и трассировка записей составляют проверяемую дисциплину верификации.
При медленном запросе сначала нужно измерить, где тратятся ресурсы, а не угадывать причину.
- Через EXPLAIN следует проверить полные сканирования таблиц, использование индексов или партиций, способ соединения и число строк на каждом этапе.
- Объём данных стоит уменьшать подходящими ранними фильтрами и выбирать только нужные колонки вместо SELECT *.
- Также нужно проверить полезные индексы на колонках соединения и фильтрации в строчно-ориентированной базе либо использование колонки партиционирования в WHERE для партиционированной системы.
Зачем это спрашивают: Диагностика от плана вместо фольклорных оптимизаций - привычка, которую интервьюеры хотят подтвердить.
DDL определяет структуры базы данных, а DML работает с данными внутри этих структур.
- К DDL относятся CREATE, ALTER и DROP для таких объектов, как таблицы, схемы и индексы.
- К DML относятся INSERT, UPDATE, DELETE и MERGE, а читающий данные SELECT иногда выделяют отдельно как DQL.
- Разрушительные команды DDL, например DROP или TRUNCATE, требуют особой осторожности, поскольку возможность отката зависит от базы, а восстановление может быть сложным или невозможным.
Зачем это спрашивают: Асимметрия отката между операциями со схемой и с данными - ожидаемый практический вывод.
Закрытые вопросы
- 21
Что такое первичный и внешний ключи и какова их роль в аналитических базах?
databaseforeign-keys - 22
Какие ограничения существуют в SQL и почему они важны для загрузок данных?
sql - 23
Что такое представление и чем отличается материализованное представление?
materialized-views - 24
Что такое транзакция и почему транзакции важны при загрузке данных?
transactions - 25
Что такое индекс и почему не индексировать каждую колонку?
indexesschema - 26
В чём разница между OLTP и OLAP базами данных?
database - 27
Что такое нормализация и какие проблемы она решает?
normalization - 28
Почему аналитические схемы намеренно денормализуют?
schemadenormalization - 29
Что такое таблицы фактов и измерений в звёздной схеме?
schemamodeling - 30
В чём разница между звёздной схемой и схемой снежинки?
schemamodelingsnowflake - 31
Что такое грануляция таблицы фактов и почему это первое решение при проектировании?
modelingdesign - 32
Что такое суррогатный ключ и почему он вместо естественного?
- 33
Что такое медленно меняющиеся измерения и в чём разница между SCD типов 1 и 2?
scd - 34
Когда вы выберете реляционную базу, а когда NoSQL-хранилище?
nosqldatabase - 35
Что такое хранилище данных и чем оно отличается от базы приложения?
databasewarehouse - 36
Что такое озеро данных и как оно соотносится с хранилищем?
warehouse - 37
Почему аналитические базы используют колоночное хранение?
databaseschema - 38
Что такое партиционирование таблиц и что оно даёт пайплайну?
partitioningci-cd - 39
В чём сильные стороны и ловушки CSV как формата данных?
- 40
Когда JSON - правильный формат в пайплайнах и какова его цена?
ci-cd - 41
Почему Parquet стал форматом по умолчанию для аналитических данных?
- 42
Система-источник добавила новую колонку в выгрузку. Что случится с пайплайном и как это правильно обрабатывать?
schemasystem-designci-cd - 43
Зачем сжимать файлы данных и что джуну знать о выборе сжатия?
- 44
Что такое объектное хранилище вроде S3 и почему дата-инженерия живёт на нём?
aws - 45
Как организовать данные в бакете, чтобы он оставался пригодным по мере роста?
- 46
Что значит идемпотентная загрузка данных и как её добиться?
idempotency - 47
В чём разница между полной и инкрементальной загрузкой?
pipelines - 48
Откуда инкрементальная загрузка знает, что нового? Объясните подход с водяным знаком.
pipelines - 49
Что такое апсерт и когда пайплайну нужен MERGE?
ci-cd - 50
Что такое dbt и какие проблемы он решает дата-команде?
dbt - 51
Что такое ETL и что происходит на каждой стадии?
etl - 52
В чём разница между ETL и ELT и почему ELT победил?
etl - 53
Спроектируйте простой пайплайн, ежедневно загружающий данные из REST API в хранилище.
restdesignwarehouse - 54
Что означают пагинация и rate limits при извлечении из API?
paginationrate-limiting - 55
Как пайплайну обращаться с записями, не прошедшими валидацию посреди прогона?
validationci-cd - 56
Что такое Airflow и что такое DAG и таски?
airflow - 57
Что такое бэкфилл и что должно быть правдой, чтобы он был безопасным?
backfill - 58
В чём разница между батчевой и потоковой обработкой и когда какая уместна?
streamingbatchconcurrency - 59
Что такое Kafka на верхнем уровне и какую проблему она решает?
kafka - 60
Что такое Spark и когда он нужен вместо pandas?
pandas - 61
Почему голого cron не хватает для оркестрации настоящих дата-пайплайнов?
pipelinesorchestrationcron - 62
Что мониторить в дата-пайплайнах, кроме того, что джоб отработал?
monitoringci-cdpipelines - 63
Что такое свежесть данных и как реализовать проверку свежести?
consistency - 64
Что должны содержать логи пайплайна, чтобы сбои были отлаживаемыми?
ci-cd - 65
Как обработать в Python CSV-файл, который больше памяти?
concurrencypythonmemory - 66
Вы загрузили файл в pandas. Что проверяете до любых преобразований?
pandas - 67
Как слияние DataFrame в pandas идёт не так и как защититься?
pandas - 68
Как вы обращаетесь с пропущенными значениями в pandas при обработке в пайплайне?
concurrencypandassoft-skills - 69
Где должны жить преобразования: в SQL или в Python?
sqlpython - 70
Как надёжно звать HTTP API из питоновского скрипта извлечения?
httppython - 71
API возвращает глубоко вложенный JSON. Как превратить его в плоские таблицы?
api - 72
Как вы управляете Python-зависимостями кода пайплайнов?
dependenciesci-cdpython - 73
Как вы тестируете код преобразований пайплайна?
ci-cd - 74
Почему SQL-модели, DAG и конфиги пайплайнов должны жить в git?
gitconfigci-cd - 75
Вы ревьюите пул-реквест пайплайна коллеги. На что смотрите?
code-reviewci-cd - 76
Какие измерения описывают качество данных и зачем называть их явно?
quality - 77
Как вы решаете проблемы качества данных в пайплайне?
qualitysoft-skillsci-cd - 78
Откуда в пайплайнах берутся дубликаты и как от них защищаться?
ci-cd - 79
Колонка, которая никогда не должна быть NULL, начинает приходить с 30 процентами NULL. Что делаете?
schemafundamentals - 80
Как проверить, что загрузка корректно перенесла все данные из источника в цель?
- 81
Как обращаться с таймстемпами и часовыми поясами в дата-платформе?
- 82
Что такое поздно прибывающие данные и как батчевые пайплайны с ними справляются?
batchci-cd - 83
Что считается персональными данными и каким правилам следовать джуну при работе с ними?
pii - 84
Как должен быть организован доступ к данным в хранилище?
warehouse - 85
Продакшен-таблицу по ошибке удалили или испортили. Какие варианты восстановления?
ownership - 86
Как устроены окружения разработки и продакшена для дата-пайплайнов?
pipelinesci-cd - 87
Что делает запросы дорогими в облачных хранилищах и как писать SQL с оглядкой на стоимость?
sqlquerieswarehouse - 88
Зачем документировать датасеты и что содержит минимально полезная документация?
documentation - 89
Вы приходите утром, а ночной прогон пайплайна упал. Пройдите по своей рутине.
ci-cd - 90
Стейкхолдер говорит, что цифры на дашборде выглядят неверными. Как расследуете?
stakeholder-managementcommunication - 91
Вам прилетает запрос: загрузи эти данные в хранилище. Что уточняете до постройки?
warehouse - 92
Нужно переименовать и перестроить таблицу, которую запрашивают другие команды. Как раскатываете ломающее изменение?
queriesversioning - 93
Ваша загрузка задвоила строки в продакшен-таблице, и отчёты ушли неверными. Что делаете?
- 94
Ad-hoc запросы данных постоянно прерывают ваш проект по пайплайнам. Как балансируете?
ci-cd - 95
Как вы растёте как джун-дата-инженер?
- 96
Сколько вы копаете проблему в одиночку, прежде чем попросить помощи?
- 97
Сеньор предлагает подход, который вы считаете неверным. Как поступаете?
soft-skills - 98
Две системы-источника расходятся по одной метрике, и оба владельца настаивают на своей правоте. Что делаете?
conflictsystem-designmonitoring - 99
Вы приходите в команду с десятками существующих пайплайнов. Как выйти на продуктивность?
joinsci-cd - 100
Какие качества делают дата-инженера сильным помимо знания инструментов?