Подготовка к собеседованию — Дата-инженер
Колода из 450+ карточек с вопросами для собеседования по направлению «Дата-инженер» — по темам и уровню сложности, с повторениями по вашим оценкам. Посмотрите несколько карточек ниже, затем выберите доступ, чтобы учить всё направление по расписанию в стиле Anki (SM-2).
Новым подписчикам месяца или года может быть доступен бесплатный пробный период 7 дней. Условия и сумму подтвердит страница оплаты.
С чего начать
Нужно писать простой код на Python и SQL и понимать устройство таблиц и файлов. На этих основах строятся Spark, стриминг и архитектура; практикуйтесь на небольшом пайплайне.
Первый проход: Python → Основы CS. Начните с базовых вопросов в этих модулях, затем продолжайте по плану. К сложным и senior-вопросам возвращайтесь по требованиям вакансии; все карточки доступны с самого начала.
Общие темы могут входить в несколько направлений и сохраняют одну историю повторений. План ниже отмечает общие основы и профильные модули; выбирайте глубину под свою вакансию.
Что внутри
Все темы направления, сгруппированные так, как вы будете их учить.
Python
102 карточкиОбщие основы
Основы CS
53 карточкиОбщие основы
Базы данных
82 карточкиОбщие основы
Моделирование данных и хранилища
12 карточекПрофильный модуль
ETL/ELT и пайплайны
18 карточекПрофильный модуль
Хранение и форматы файлов
13 карточекПрофильный модуль
Spark и распределённая обработка
13 карточекПрофильный модуль
Стриминг и Kafka
14 карточекПрофильный модуль
Kafka и очереди
21 карточкаОбщие основы
SQL и оптимизация запросов
10 карточекПрофильный модуль
ClickHouse
8 карточекПрофильный модуль
Качество данных и оркестрация
10 карточекПрофильный модуль
DevOps и инфраструктура
47 карточекОбщие основы
Архитектура данных и системный дизайн
9 карточекПрофильный модуль
Поведенческое интервью
38 карточекОбщие основы
Примеры вопросов
Несколько карточек из колоды — откройте ответ, затем выберите доступ, чтобы учить весь набор по расписанию.
Чем отличаются изменяемые (mutable) и неизменяемые (immutable) типы?
Чем отличаются изменяемые (mutable) и неизменяемые (immutable) типы?
Короткий ответ: Изменяемый объект можно менять на месте (list, dict, set), неизменяемый — нельзя (int, str, tuple). Перепривязка переменной и изменение объекта — разные действия.
items = [1, 2]
alias = items
items.append(3)
assert alias is items and alias == [1, 2, 3]
text = "hello"
original = text
text += " world"
assert original == "hello" # исходная строка не изменилась
Подробно:
id()идентифицирует объект и постоянен в течение его жизни. То, что это адрес памяти, — деталь реализации CPython.- В кортеже нельзя заменить элементы, но вложенный список может изменяться. Неизменяемость не означает автоматически глубокую неизменяемость или потокобезопасность.
- Ключ словаря и элемент множества должны быть хешируемыми: хеш остаётся стабильным, а равные объекты имеют равные хеши. Кортеж со списком нехешируем. Изменяемый экземпляр пользовательского класса может хешироваться по идентичности: хешируемость не синоним неизменяемости.
- Функция получает ссылки на объекты. Мутация аргумента может быть видна вызывающему коду; перепривязка локального параметра не перепривязывает переменную снаружи.
Источники: Хешируемость Python, идентичность объектов.
В чём разница между concurrency и parallelism?
В чём разница между concurrency и parallelism?
Короткий ответ: Конкурентность — это про структуру программы (управление несколькими задачами, которые прогрессируют, но не обязательно одновременно). Параллелизм — это про физическое одновременное выполнение на нескольких ядрах.
Подробно:
- Конкурентность (concurrency) — задачи переключаются и продвигаются «по очереди», создавая иллюзию одновременности. Один повар готовит 3 блюда, переключаясь между ними. Может быть и на одном ядре.
- Параллелизм (parallelism) — задачи реально выполняются в одну и ту же физическую секунду. Три повара, каждый готовит своё блюдо. Требует нескольких ядер/процессоров.
Конкурентность (1 ядро): Параллелизм (2 ядра):
CPU: A B A B A B CPU0: A A A A
CPU1: B B B B
В Python:
asyncioиthreading(из-за GIL) дают конкурентность, но не настоящий параллелизм для CPU-кода.multiprocessingдаёт настоящий параллелизм.
💡 «Concurrency is about dealing with lots of things at once. Parallelism is about doing lots of things at once.» — Rob Pike.
⚠️ Ловушка: многие путают и говорят «потоки в Python работают параллельно». Для CPU-bound кода это не так из-за GIL.
Зачем нужны type hints, если Python динамический?
Зачем нужны type hints, если Python динамический?
Короткий ответ: Аннотации типов не проверяются интерпретатором в рантайме — они нужны для статического анализа (mypy, pyright), автодополнения в IDE, документации и раннего обнаружения ошибок до запуска кода. Python остаётся динамическим, hints — это «контракт», который проверяют внешние инструменты.
Подробно:
Type hints (PEP 484) не влияют на выполнение программы. Интерпретатор их игнорирует — можно передать строку туда, где ожидается int, и код не упадёт сам по себе.
def add(a: int, b: int) -> int:
return a + b
# Python НЕ проверяет типы — это выполнится без ошибок:
print(add("a", "b")) # "ab" — конкатенация строк!
# Но mypy выдаст ошибку ДО запуска:
# error: Argument 1 to "add" has incompatible type "str"; expected "int"
Зачем тогда нужны:
- Раннее обнаружение ошибок —
mypy/pyrightловят несовпадения типов до прода. - Автодополнение и навигация в IDE (PyCharm, VS Code).
- Документация — сигнатура
def f(x: list[int]) -> dict[str, int]понятнее комментария. - Рефакторинг — при изменении типа инструмент покажет все места, где он используется.
- Контракты в больших командах — снижают «неявные» договорённости.
# Без hints — непонятно, что ожидается:
def process(data, config): ...
# С hints — самодокументируемо:
def process(data: list[dict[str, int]], config: "Config") -> bool: ...
⚠️ Ловушка: Аннотации — не валидация: def f(x: int) не запретит передать строку в рантайме. Для проверки входных данных нужны pydantic или явные проверки с raise — не assert, который при запуске с python -O удаляется.
Что такое Big O нотация?
Что такое Big O нотация?
Короткий ответ: Big O описывает, как растёт время работы или потребление памяти алгоритма при увеличении размера входных данных n, отбрасывая константы и младшие члены. Это верхняя оценка скорости роста.
Подробно:
Big O отвечает на вопрос «что произойдёт, когда n станет очень большим?». Нас не интересует точное число операций, а только характер роста. Поэтому O(2n + 100) упрощается до O(n), а O(3n² + n) — до O(n²).
Основные классы роста (от лучшего к худшему):
# O(1) — константа: не зависит от n
def first(arr):
return arr[0] if arr else None
# O(log n) — логарифм: каждый шаг делит задачу пополам (бинарный поиск)
def binary_search(arr, target):
lo, hi = 0, len(arr) - 1
while lo <= hi:
mid = (lo + hi) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
lo = mid + 1
else:
hi = mid - 1
return -1
# O(n) — линейная: один проход
def total(arr):
s = 0
for x in arr: # n итераций
s += x
return s
# O(n log n) — эффективные сортировки (merge, quick в среднем, Timsort)
def sort_it(arr):
return sorted(arr)
# O(n^2) — квадрат: вложенный цикл
def has_dup_naive(arr):
for i in range(len(arr)):
for j in range(i + 1, len(arr)):
if arr[i] == arr[j]:
return True
return False
# O(2^n) — экспонента: наивный Фибоначчи, перебор подмножеств
def fib_naive(n):
if n < 2:
return n
return fib_naive(n - 1) + fib_naive(n - 2)
Как оценивать код: последовательные шаги складываются, и остаётся старший член (O(n) + O(n log n) = O(n log n)); вложенные циклы перемножаются (O(n·m), при m = n — O(n²)); отбрасывание половины задачи с постоянной работой на шаге даёт O(log n). Если входов два, сохраняйте обе переменные: O(n + m) нельзя сокращать до O(n), пока не известно, что m ≤ n.
⚠️ Ловушка: Big O — это про асимптотику (поведение при больших n), а не про реальное время. O(n) алгоритм может быть медленнее O(n²) на маленьких данных из-за больших констант. Также путают: Big O (верхняя граница, Ω — нижняя, Θ — точная), в собесах под «O» обычно подразумевают Θ.
Что делает SELECT и в каком порядке выполняются части запроса?
Что делает SELECT и в каком порядке выполняются части запроса?
Короткий ответ: SELECT извлекает строки из таблиц. Логический порядок выполнения НЕ совпадает с порядком написания: сначала FROM, затем WHERE, GROUP BY, HAVING, SELECT, DISTINCT, ORDER BY, LIMIT.
Подробно:
Порядок написания (синтаксический):
SELECT DISTINCT col1, agg(col2)
FROM t
WHERE cond
GROUP BY col1
HAVING agg_cond
ORDER BY col1
LIMIT 10 OFFSET 20;
Логический порядок исполнения:
1. FROM / JOIN -- какие таблицы, как соединить
2. WHERE -- фильтр строк ДО группировки
3. GROUP BY -- группировка
4. HAVING -- фильтр групп ПОСЛЕ агрегации
5. SELECT -- выражения, алиасы, оконные функции
6. DISTINCT -- удаление дублей
7. ORDER BY -- сортировка
8. LIMIT / OFFSET -- срез
⚠️ Ловушка: алиас из SELECT нельзя использовать в WHERE (т.к. WHERE выполняется раньше SELECT), но можно в ORDER BY и часто в GROUP BY (зависит от СУБД). Пример ошибки:
SELECT salary * 12 AS annual FROM emp WHERE annual > 100000; -- ОШИБКА
SELECT salary * 12 AS annual FROM emp ORDER BY annual; -- ОК
Что такое индекс и зачем он нужен?
Что такое индекс и зачем он нужен?
Короткий ответ: Индекс — это отдельная структура данных, которая хранит значения одной или нескольких колонок в упорядоченном/организованном виде вместе с указателями на физическое расположение строк (TID — tuple identifier), чтобы база могла находить строки без полного сканирования таблицы.
Подробно: Без индекса PostgreSQL вынужден читать всю таблицу (Sequential Scan) и проверять каждую строку. Индекс позволяет за O(log n) (для B-tree) найти нужные TID и потом сходить за самими строками в heap (основную область хранения таблицы).
CREATE INDEX idx_users_email ON users (email);
-- Теперь запрос ищет по дереву, а не по всей таблице
SELECT * FROM users WHERE email = 'a@b.com';
Физически таблица в Postgres хранится в виде heap — неупорядоченного набора страниц по 8 КБ. Индекс — это «оглавление» к этому heap. У одной таблицы может быть много индексов.
⚠️ Ловушка: Индекс ускоряет чтение, но замедляет запись (каждый INSERT/UPDATE/DELETE должен поддерживать индекс актуальным). Индекс на каждую колонку «на всякий случай» — антипаттерн.
Готовы лучше запоминать?
Посмотрите пример, выберите направление и настройте регулярную практику под свою подготовку.
Вопросы об этом направлении
Как готовиться к собеседованию на «Дата-инженер»?
Учите концепции, которые придётся объяснять, а не только те, что умеете кодить. Направление «Дата-инженер» в RecallDeck даёт 450+ отобранных вопросов и возвращает каждый по расписанию в стиле Anki (SM-2), основанному на ваших оценках — чтобы тренировать вспоминание и объяснение. Дополняйте повторения кодингом и пробными собеседованиями.
Какие темы охватывает направление «Дата-инженер»?
Направление «Дата-инженер» разбито на ключевые области, которые реально проверяют на таких собеседованиях, — по темам и уровню сложности (Concept, Junior, Middle, Senior). Полный план и примеры вопросов можно посмотреть выше до входа.
Помогает ли интервальное повторение в подготовке к «Дата-инженер»?
Да. Активное вспоминание и честная самооценка помогают закреплять знания. RecallDeck назначает повторения карт по направлению «Дата-инженер» на основе ваших оценок: знакомые карты возвращаются реже, а сложные получают больше практики.
Можно попробовать направление «Дата-инженер» до оплаты?
Новым подписчикам месячного или годового тарифа может быть доступен пробный период 7 дней со всем направлением «Дата-инженер» и всеми функциями. Право на него и сумму подтвердит страница оплаты; при повторной подписке списание может быть сразу. Отмените подписку онлайн до конца пробного периода, чтобы избежать первого списания. У вечного доступа пробного периода нет.