SQL собеседование Middle 2026 — 8 вопросов с ответами
S.
Sobes AI

Вопросы по SQL на собеседовании — часть 2/3: Middle с разбором ответов

15.03.2026 | 3 мин чтения | 4 просмотров

Это часть 2 из 3. ← Часть 1: Junior | Часть 3: Senior →

Вопросы по SQL на собеседовании — часть 2/3: Middle с разбором ответов

TL;DR: 8 вопросов для мидлов, которые проверяют глубину понимания SQL — не синтаксис, а то, как работает СУБД «под капотом». Индексы, транзакции, порядок выполнения запросов и подзапросы — по данным собеседований 2024–2026.

Как пользоваться: Открой перед собеседованием → пройдись по каждому вопросу → если follow-up вызывает затруднение — это зона роста. Базовые вопросы — в части 1 (Junior).

Если Junior-уровень — это «знаю синтаксис», то Middle — это «понимаю, почему запрос работает медленно и как это исправить». На этом уровне интервьюер проверяет не умение писать SELECT, а способность проектировать и оптимизировать.

По данным анализа 9 247 технических собеседований за 2024–2026 годы, индексы обсуждаются в 27% бэкенд-интервью, а задачи на оптимизацию запросов — в 19%.

Содержание


9. В каком порядке выполняется SQL-запрос?

Интервьюер проверяет: понимаешь ли ты, почему одни конструкции работают, а другие — нет.

Порядок написания и порядок выполнения — разные вещи:

Порядок выполнения:

  1. FROM / JOIN — определить таблицы и связи
  2. WHERE — отфильтровать строки
  3. GROUP BY — сгруппировать
  4. HAVING — отфильтровать группы
  5. SELECT — выбрать столбцы и вычислить выражения
  6. DISTINCT — убрать дубликаты
  7. ORDER BY — отсортировать
  8. LIMIT / OFFSET — ограничить результат

Вот почему нельзя использовать алиас из SELECT в WHERE:

-- Не работает: alias ещё не существует на этапе WHERE
SELECT salary * 12 AS annual_salary
FROM employees
WHERE annual_salary > 100000;  -- ошибка!

-- Работает: ORDER BY выполняется ПОСЛЕ SELECT
SELECT salary * 12 AS annual_salary
FROM employees
ORDER BY annual_salary DESC;

Типичная ошибка: путают порядок написания и выполнения. Многие не могут объяснить, почему HAVING «видит» агрегатные функции, а WHERE — нет.

Follow-up: Почему MySQL позволяет использовать алиас в HAVING, а PostgreSQL — не всегда? MySQL расширяет стандарт SQL и позволяет ссылаться на алиасы SELECT в HAVING. PostgreSQL строже следует стандарту.


10. Что такое подзапрос? Коррелированный vs некоррелированный

Интервьюер проверяет: видишь ли ты разницу в производительности между двумя подходами.

Некоррелированный подзапрос выполняется один раз, его результат используется внешним запросом:

-- Сотрудники с зарплатой выше средней (подзапрос выполнится 1 раз)
SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

Коррелированный подзапрос ссылается на внешний запрос и выполняется для КАЖДОЙ строки:

-- Сотрудники с зарплатой выше средней В СВОЁМ отделе
SELECT name, salary, department_id
FROM employees e
WHERE salary > (
    SELECT AVG(salary)
    FROM employees
    WHERE department_id = e.department_id  -- ссылка на внешний запрос
);

Типичная ошибка: не думают о производительности. Коррелированный подзапрос на таблице в миллион строк — это миллион вложенных запросов. Часто можно переписать через JOIN или оконные функции.

Follow-up: Как переписать коррелированный подзапрос через JOIN?

SELECT e.name, e.salary, e.department_id
FROM employees e
JOIN (
    SELECT department_id, AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department_id
) dept_avg ON e.department_id = dept_avg.department_id
WHERE e.salary > dept_avg.avg_salary;

11. Как работают индексы и когда их использовать?

Интервьюер проверяет: понимаешь ли ты trade-off между скоростью чтения и записи.

Индекс — это отдельная структура данных (чаще всего B-tree), которая ускоряет поиск строк. Аналогия: алфавитный указатель в книге — не нужно читать все 500 страниц, чтобы найти термин.

-- Создание индекса
CREATE INDEX idx_employees_email ON employees(email);

-- Составной индекс (порядок столбцов важен!)
CREATE INDEX idx_orders_customer_date ON orders(customer_id, created_at);

Когда индексы помогают:

  • Столбцы в WHERE, JOIN, ORDER BY
  • Столбцы с высокой кардинальностью (много уникальных значений)
  • Таблицы с частым чтением

Когда индексы вредят:

  • Таблицы с частой записью (INSERT/UPDATE/DELETE замедляются)
  • Столбцы с низкой кардинальностью (пол, булевы значения)
  • Маленькие таблицы (полный скан быстрее)

Типичная ошибка: «индексы ускоряют всё» — нет. Каждый индекс — это дополнительная структура, которую СУБД обновляет при каждом INSERT/UPDATE/DELETE.

Follow-up: Что такое составной индекс и почему порядок столбцов важен? Индекс (customer_id, created_at) эффективен для поиска по customer_id или по customer_id + created_at. Но НЕ эффективен для поиска только по created_at (правило «leftmost prefix»).


Три вопроса позади — и мы перешли от синтаксиса к пониманию «как это работает внутри». Дальше — транзакции, изоляция и проектирование. Сложность растёт.


12. Что такое транзакция и свойства ACID?

Интервьюер проверяет: понимаешь ли ты, как СУБД гарантирует целостность данных.

Транзакция — это группа операций, которые выполняются как одно целое: либо все успешно, либо ни одна.

BEGIN;
UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
UPDATE accounts SET balance = balance + 1000 WHERE id = 2;
COMMIT;  -- обе операции применяются
-- или ROLLBACK; — обе отменяются

ACID:

  • Atomicity (атомарность) — всё или ничего
  • Consistency (согласованность) — данные переходят из одного корректного состояния в другое
  • Isolation (изоляция) — параллельные транзакции не мешают друг другу
  • Durability (долговечность) — после COMMIT данные сохранены, даже если сервер упадёт

Типичная ошибка: путают Consistency в ACID и Consistency в CAP-теореме. В ACID — это про бизнес-правила и ограничения (constraints). В CAP — про одинаковость данных на разных узлах.

Follow-up: Что происходит, если во время транзакции упадёт сервер? СУБД использует WAL (Write-Ahead Log): перед изменением данных запись попадает в лог. При рестарте незавершённые транзакции откатываются, завершённые — восстанавливаются.


13. Какие бывают уровни изоляции транзакций?

Интервьюер проверяет: понимаешь ли ты компромисс между целостностью данных и производительностью.

Четыре уровня от слабого к строгому:

Read Uncommitted — транзакция видит незакоммиченные изменения других транзакций (грязное чтение). Практически не используется.

Read Committed — видит только закоммиченные данные. Дефолт в PostgreSQL и Oracle. Возможно неповторяемое чтение: два SELECT в одной транзакции могут вернуть разные данные.

Repeatable Read — повторные чтения возвращают одинаковый результат. Дефолт в MySQL InnoDB. Возможны фантомные чтения (новые строки, вставленные другой транзакцией).

Serializable — полная изоляция, транзакции выполняются как будто последовательно. Самый медленный, но самый надёжный.

-- PostgreSQL: установить уровень изоляции
BEGIN;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT * FROM accounts WHERE id = 1;
-- ... другие операции ...
COMMIT;

Типичная ошибка: заучивают таблицу «уровень — аномалия», но не могут привести реальный пример, когда это важно.

Реальный пример: система бронирования билетов. Два пользователя одновременно видят «1 место свободно». Без нужного уровня изоляции оба забронируют одно место.

Follow-up: Какой уровень изоляции по умолчанию в PostgreSQL? Read Committed. А в MySQL InnoDB? Repeatable Read.


14. Что такое нормализация? Когда нужна денормализация?

Интервьюер проверяет: можешь ли ты проектировать схему БД с учётом trade-offs.

Нормализация — процесс разбиения таблиц для устранения избыточности данных. Основные формы:

  • 1NF: каждая ячейка содержит одно значение (не массив, не список)
  • 2NF: 1NF + каждый неключевой столбец зависит от всего ключа (не от его части)
  • 3NF: 2NF + нет транзитивных зависимостей (столбец зависит только от ключа, не от другого неключевого столбца)
-- НЕ 1NF: теги в одном поле
-- | id | title       | tags                  |
-- |----|-------------|-----------------------|
-- | 1  | SQL Guide   | sql, database, guide  |

-- 1NF: отдельная таблица для связи
CREATE TABLE post_tags (
    post_id INT REFERENCES posts(id),
    tag_id INT REFERENCES tags(id),
    PRIMARY KEY (post_id, tag_id)
);

Денормализация — осознанное добавление избыточности для ускорения чтения. Используется в:

  • OLAP-системах и хранилищах данных
  • Кэширующих таблицах с предрассчитанными значениями
  • Ситуациях, где JOIN десятков таблиц слишком дорог

Типичная ошибка: говорят «нормализация — хорошо, денормализация — плохо» без контекста. На практике выбор зависит от паттерна нагрузки: много записей → нормализация, много чтений → возможна денормализация.

Follow-up: Приведи пример денормализации. Интернет-магазин хранит total_price прямо в таблице заказов, хотя его можно вычислить из позиций. Это денормализация: дублирование ради скорости.


15. Что такое VIEW и зачем оно нужно?

Интервьюер проверяет: знаешь ли ты инструменты абстракции данных.

VIEW — виртуальная таблица, определённая SQL-запросом. Не хранит данные, а вычисляет их при каждом обращении.

CREATE VIEW active_employees AS
SELECT id, name, email, department_id
FROM employees
WHERE status = 'active' AND terminated_at IS NULL;

-- Используется как обычная таблица
SELECT * FROM active_employees WHERE department_id = 5;

Зачем:

  • Упрощает сложные запросы (абстракция)
  • Ограничивает доступ к данным (безопасность — прячет столбцы с зарплатами)
  • Обеспечивает обратную совместимость (структура таблицы менялась, VIEW — нет)

Типичная ошибка: путают VIEW и MATERIALIZED VIEW. Обычный VIEW — это сохранённый запрос, данные вычисляются каждый раз. MATERIALIZED VIEW — физически хранит результат, нужно обновлять вручную (REFRESH).

Follow-up: Можно ли делать INSERT/UPDATE через VIEW? В простых случаях — да (если VIEW основан на одной таблице без агрегаций). В сложных — нет.


16. Что такое self-join и когда его используют?

Интервьюер проверяет: можешь ли ты работать с иерархическими данными.

Self-join — соединение таблицы с самой собой. Используется, когда строки в таблице связаны друг с другом.

Классический пример — иерархия сотрудников:

-- Таблица employees: id, name, manager_id (ссылается на id этой же таблицы)
SELECT
    e.name AS employee,
    m.name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;

Другой пример — найти пары сотрудников из одного города:

SELECT
    a.name AS employee_1,
    b.name AS employee_2,
    a.city
FROM employees a
JOIN employees b ON a.city = b.city AND a.id < b.id;
-- a.id < b.id чтобы не получить дубликаты (Иван-Петр и Петр-Иван)

Типичная ошибка: забывают условие a.id < b.id (или a.id != b.id) — получают дубликаты и пары элемента с самим собой.

Follow-up: Как вывести всю цепочку подчинения (сотрудник → руководитель → руководитель руководителя)? Через рекурсивный CTE — это уже Senior-уровень, разберём в части 3.


Итого Middle: 8 вопросов. Фокус — порядок выполнения, индексы, транзакции, проектирование. Если уверенно объясняешь trade-off между нормализацией и денормализацией и знаешь, когда индекс замедляет систему — ты готов к Middle-собесу.


Как попробовать Sobes AI

Sobes AI — ИИ-ассистент, который помогает на техническом собеседовании в реальном времени. Подсказывает ответы, пока ты общаешься с интервьюером.

  1. Зайди на sobesai.app и скачай приложение
  2. Запусти перед собеседованием
  3. Sobes AI слушает вопрос и подсказывает структурированный ответ
  4. Работает с SQL, базами данных и другими техническими темами

Это часть 2 из 3. ← Часть 1: Junior | Часть 3: Senior →

Готовитесь к собеседованию?

Sobes AI слушает вопросы интервьюера и генерирует ответы в реальном времени.

Скачать Sobes AI