Топ-15 вопросов для интервью с СУБД

Автор: Дмитрий Иванов [Команда P9X]

~8 минут чтения

Рекрутеры больше не просят вас перечислять шесть нормальных форм. Они хотят услышать ваши рассуждения о данных в 2 часа ночи, когда главный шард загружен, а финансовый директор отвечает заинтересованным сторонам. Вопросы, которые вы встретите в этой статье, были взяты из реальных интервью в Google, Amazon, Stripe, Snowflake и некоторых стартапах из программы YC.

Метрика для разделения

Я разделил вопросы на три категории. Каждая категория адаптирована под определённый уровень опыта и постепенно усложняется. В списке есть как теоретические вопросы, которые задают во время интервью, так и практические дополнения, чтобы учесть прагматику.

Начинающие

Эти вопросы актуальны для тех, кто всё ещё осваивает основы.

Вопрос 1. Что такое первичный ключ и почему мы не можем просто использовать ROWID?

A. Первичный ключ — это логический, уникальный идентификатор, выбранный разработчиком. ROWID (или CTID, _id и т. д.) — это физический локатор, поддерживаемый механизмом, который может измениться после операций обслуживания, таких как VACUUM, переупорядочивание кластера или балансировка шардов. Предоставление физического указателя нарушило бы отношения внешнего ключа в тот момент, когда уровень хранения переорганизует страницы. Первичный ключ, напротив, неизменен и переносится между механизмами хранения, что именно и требуется для ссылочной целостности.

Вопрос 2. Объясните логическую независимость данных по сравнению с физической независимостью данных.

A. Логическая независимость данных означает, что вы можете изменить логическую схему (например, добавив атрибуты или новые таблицы), не переписывая прикладные программы. Физическая независимость данных означает, что вы можете изменить структуру хранения (например, индексы, организацию файлов) без влияния на логическую схему или запросы.

Вопрос 3. Определите 1NF, 2NF и 3NF в одном абзаце каждый, затем скажите мне, какой из них вы бы ослабили в первую очередь для аналитики.

A. 1NF: каждый столбец содержит атомарные, неделимые значения (без массивов или вложенных таблиц). 2NF: 1NF плюс каждый неключевой столбец полностью зависит от всего первичного ключа (без частичной зависимости). 3NF: 2NF плюс отсутствие транзитивной зависимости — неключевые столбцы не могут зависеть от других неключевых столбцов. В аналитике со звёздной схемой мы обычно сначала отказываемся от 3NF: мы с радостью дублируем название сегмента клиента в таблице фактов, чтобы сэкономить на объединении, принимая аномалии обновления ради скорости чтения.

Вопрос 4. В чём разница между схемой и экземпляром в СУБД?

A. Схема — это общий дизайн базы данных (её чертёж), обычно фиксированный и редко изменяемый. Экземпляр — это фактическое содержимое базы данных в данный момент. Схема стабильна; экземпляр меняется каждый раз, когда данные обновляются.

Вопрос 5. Перечислите четыре свойства ACID и дайте одно предложение, иллюстрирующее нарушение каждого из них.

A. Атомарность: дебет проведён, но кредит исчез, и деньги исчезли. Согласованность: написано отрицательное сальдо; ограничение проверки срабатывает, и вся транзакция откатывается. Изоляция: два одновременных бронирования занимают последнее место; оба фиксируются, что приводит к перепродаже рейса. Долговечность: фиксация возвращает успех, питание отключается, журнал упреждающей записи находится на повреждённом SSD, что приводит к потере данных.

Вопрос 6. Какие существуют типы моделей данных в СУБД?

A. Распространённые модели включают:

  • объектно-ориентированная модель (объекты, классы, наследование);
  • иерархическая модель (древовидная структура, родитель-потомок);
  • сетевая модель (записи, соединённые ссылками);
  • реляционная модель (таблицы, ключи, отношения);
  • модель «сущность-связь» (высокоуровневая концептуальная).

У вас есть некоторый опыт работы с базами данных.

Вопрос 7. Что такое взаимоблокировка в СУБД? Как с ней можно справиться?

A. Взаимоблокировка возникает, когда две транзакции удерживают ресурс и ждут ресурса другой, блокируя друг друга навсегда. Решения:

  • предотвращение (алгоритм банкира);
  • предотвращение (порядок блокировки, тайм-ауты);
  • обнаружение (граф ожидания, обнаружение циклов).

Вопрос 8. Что такое checkpointing в восстановлении СУБД?

A. Контрольный момент — это маркер, при котором СУБД сбрасывает грязные страницы и журналы в стабильное хранилище. Во время восстановления после сбоя система может начать с последнего контрольного момента вместо сканирования всего журнала, что ускоряет восстановление.

Вопрос 9. Что на самом деле делает оптимизатор при выборе cost-based соединения между вложенным циклом, хешем и слиянием?

A. Он оценивает количество элементов каждого дочернего элемента, обращается к статистике столбцов (наиболее частые значения, гистограммы), учитывает доступную память (work_mem), индексы и сортировки. Если внешняя сторона небольшая (после фильтров) и внутренняя сторона имеет выборочный индекс, выигрывает вложенный цикл. Обе стороны большие и не отсортированы, что создаёт хэш-таблицу в памяти (хэш-соединение). Если обе уже отсортированы (сканирование индекса или предыдущий шаг сортировки), слияние соединений является O(n+m) и экономичным по памяти. Окончательное число затрат — это I/O + CPU, взвешенные эмпирическими константами, хранящимися в pg_statistic или mysql.column_stats.

Вопрос 10. Объясните фантомное чтение и какой уровень изоляции предотвращает его.

A. Транзакция A выполняет SELECT SUM(amount) WHERE status='PENDING' дважды; между запусками транзакция B вставляет новую ожидающую строку. A видит другую сумму — фантом. Только SERIALIZABLE (или Snapshot Isolation с предикатными блокировками) предотвращает фантомы; REPEATABLE READ не предотвращает (вопреки фольклору в MySQL).

Продвинутые

Вы удалили производственные данные и пережили это.

Вопрос 11. Ваша таблица на 2 ТБ должна быть шардирована. Дайте точное дерево решений о выборе ключа шардирования, которое вы бы защищали перед техническим директором.

A. 1: перечислите 10 наиболее частых запросов по частоте и пропускной способности — шардирование должно удовлетворять обоим. 2: выберите столбец с высокой кардинальностью, равномерно распределённый (user_id, а не country_code). 3: убедитесь, что столбец появляется в каждой многострочной транзакции; в противном случае неизбежен двухфазный коммит. 4: проверьте наличие риска возникновения горячих точек (например, один пользователь-знаменитость) — используйте hash-shard + per-shard autoincrement, а не range-shard. 5: докажите, что вы можете перешардировать онлайн с помощью логической репликации; представьте сценарий пробного запуска. Только когда все пять пунктов отмечены, вы подписываете проектную документацию.

Вопрос 12. Проведите меня через внутренние шаги, которые PostgreSQL выполняет от оператора INSERT до байта на устойчивом диске.

A. 1: парсер → необработанное дерево разбора. 2: анализатор → дерево запросов с типами. 3: планировщик → одноузловой план ModifyTable. 4: исполнитель захватывает блокировку буфера на целевой странице, вставляет кортеж и устанавливает системные столбцы xmin/xmax. 5: запись WAL вставлена в общие буферы в памяти. 6: COMMIT записывает WAL на диск через XLogWrite — теперь устойчив к сбоям. 7: фоновый писатель позже сбрасывает грязные страницы данных; если сервер выключается до этого, восстановление повтора воспроизводит WAL. Долговечность гарантирована на шаге 6, а не на шаге 7.

Вопрос 13. Спроектируйте битемпоральную таблицу, которая хранит действительное время (когда факт был верен в реальности) и время транзакции (когда база данных узнала об этом). Напишите первичный ключ и SQL для исправления ретроактивного изменения цены.

A. Первичный ключ: (product_id, valid_from, transaction_from). Исправление — это вставка только для добавления с новым transaction_from; без UPDATEs.

INSERT INTO price(product_id, price, valid_from, valid_to, transaction_from, transaction_to)
VALUES (42, 19.99, '2025-07-01', '2025-12-31', now(), '9999-12-31');

Чтобы завершить предыдущее некорректное утверждение:

UPDATE price SET transaction_to = now()
WHERE product_id = 42 AND valid_from <= '2025-07-01' AND valid_to > '2025-07-01'
AND transaction_to = '9999-12-31';

Выбирает FOR SYSTEM_TIME AS OF и BETWEEN valid_from AND valid_to для получения правильного временного среза.

Заключение

Список состоит из эклектичной смеси вопросов от практических до чисто теоретических. Это означает, что вас проверяют на понимание СУБД, а не на синтаксис: ключи и нормализация, ACID и аномалии изоляции, планирование запросов, восстановление и WAL, взаимоблокировки, стратегия выбора ключа шардирования, внутренние механизмы Postgres и битемпоральное моделирование. Цель — выявить компромиссы, инварианты, режимы отказа и операционные суждения.

Не заучивайте наизусть предложения. Покажите, почему первичные ключи переживают ROWIDs, когда REPEATABLE READ всё ещё допускает фантомы, почему хэш-соединение превосходит вложенные циклы и как вы перешардируете без простоев. Если вы сможете вслух изложить эти решения, вы покажете себя инженером данных.