Реляционные базы данных: как устроены и что о них спрашивают на собеседовании
Реляционные базы придумали в семидесятых, и с тех пор их регулярно хоронят: то NoSQL заменит, то объектные хранилища, то что-нибудь ещё. А PostgreSQL и MySQL по-прежнему стоят под большинством продуктов, и вопросы про них есть на любом техническом собеседовании, где вообще есть данные.
Разберём модель по существу.
Идея, на которой всё держится
Данные лежат в таблицах, таблица это набор строк с одинаковой структурой. Связи между таблицами выражаются не ссылками в памяти, а совпадением значений: в заказе лежит идентификатор клиента, по нему находится строка в таблице клиентов.
Из этого следует главное свойство: одни и те же данные можно запрашивать как угодно, не переписывая хранилище. Вы не заложили заранее, что кто-то захочет посчитать средний чек по регионам, но запрос всё равно напишется.
Второе следствие: за гибкость платят соединениями. Чем нормальнее разложены данные, тем больше JOIN в запросах.
Ключи и связи
Первичный ключ однозначно определяет строку. Обычно суррогатный: автоинкремент или UUID, а не «фамилия плюс дата рождения», потому что естественные ключи имеют привычку меняться.
Внешний ключ ссылается на первичный ключ другой таблицы. Он же обеспечивает целостность: база не даст удалить клиента, у которого есть заказы, если вы этого не разрешили явно.
Связи бывают трёх видов. Один к одному встречается редко, обычно как вынос редко используемых полей. Один ко многим это основа основ: у клиента много заказов. Многие ко многим требует промежуточной таблицы: студенты и курсы связываются через таблицу записей.
На собеседовании часто просят спроектировать схему под описание. Ждут не идеала, а понимания: правильные ключи, отсутствие дублирования, разумные типы, продуманное поведение при удалении.
Нормализация: зачем и до какого предела
Нормализация это раскладывание данных так, чтобы каждый факт хранился в одном месте.
Первая форма: в ячейке одно значение, а не список через запятую. Вторая: все неключевые поля зависят от ключа целиком. Третья: неключевые поля не зависят друг от друга. Дальше есть ещё формы, но на практике до них доходят редко.
Смысл в том, чтобы изменение одного факта требовало одной правки. Если название категории хранится в каждой строке товаров, переименование категории превращается в массовое обновление, а при сбое половина строк останется со старым названием.
Обратная сторона: нормализованная схема требует больше соединений и работает медленнее на чтение. Поэтому в аналитических хранилищах данные наоборот денормализуют, а в продуктовых базах ищут баланс.
Классический вопрос на интервью: «когда денормализация оправдана?» Хороший ответ звучит так: когда чтение сильно преобладает над записью, соединения стали узким местом, а риск рассогласования вы понимаете и контролируете.
Транзакции и ACID
Транзакция это набор операций, который выполняется целиком или не выполняется вообще. Классический пример с переводом денег: списание и зачисление либо оба произошли, либо ни одного.
Четыре свойства, которые за этим стоят:
Атомарность. Всё или ничего.
Согласованность. База переходит из одного корректного состояния в другое, ограничения не нарушаются.
Изолированность. Параллельные транзакции не видят промежуточных состояний друг друга. Степень этой невидимости регулируется уровнем изоляции.
Долговечность. После подтверждения данные переживут падение сервера.
Про уровни изоляции спрашивают почти всегда. Смысл в том, какими аномалиями вы готовы пожертвовать ради скорости: грязное чтение, неповторяемое чтение, фантомы. Чем строже уровень, тем больше блокировок и меньше параллелизма.
Индексы: коротко
Индекс это отдельная структура, которая позволяет находить строки, не перебирая таблицу целиком. Плата за него: замедление вставок и обновлений плюс место на диске.
Главное, что стоит понимать: индекс помогает, когда выбирается небольшая часть строк. Если запрос всё равно читает половину таблицы, база предпочтёт полный проход, и это разумно.
Подробнее устройство и типичные ошибки разбирали отдельно в статье про индексы в базе данных.
Реляционные базы против NoSQL
Вопрос «что выбрать» на собеседовании проверяет не знание модных названий, а понимание компромиссов.
Реляционные базы дают строгую схему, транзакции и произвольные запросы. Платят за это тем, что горизонтальное масштабирование сложнее.
Документные и ключ-значение хранилища дают гибкую схему и простое масштабирование, но за произвольные запросы и согласованность приходится отвечать приложению.
Практический ответ обычно звучит так: начинать с реляционной базы, потому что она предсказуема и покрывает большинство сценариев, а специализированные хранилища добавлять под конкретные задачи, например кеш или полнотекстовый поиск.
Что чаще всего спрашивают
Спроектируйте схему под задачу. Чем отличается первичный ключ от уникального. Что произойдёт при удалении родительской записи. Как устроены транзакции и уровни изоляции. Зачем нужны индексы и когда они не работают. Что такое нормализация и когда от неё отступают. Чем реляционная база отличается от документной.
Отдельно почти всегда идёт живой SQL: джойны, группировки, оконные функции.
Как готовиться
Теорию по базам легко прочитать и так же легко забыть, потому что она абстрактна, пока не столкнёшься с последствиями. Помогает практика: развернуть локально PostgreSQL, создать схему, набить данными, посмотреть планы запросов, поломать целостность и посмотреть, что скажет база.
А проверять себя удобно вопросами. В Сеньорчике есть блоки по SQL, базам данных и хранилищам: вопросы с реальных собеседований, с вариантами ответов и разбором каждого, а движок возвращает темы, где вы ошибаетесь. Десять минут в день в Telegram, начать можно бесплатно.