Вопросы по SQL на собеседовании — часть 2/3: Middle с разбором ответов
Это часть 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-запрос?
- 10. Что такое подзапрос? Коррелированный vs некоррелированный
- 11. Как работают индексы и когда их использовать?
- 12. Что такое транзакция и свойства ACID?
- 13. Какие бывают уровни изоляции транзакций?
- 14. Что такое нормализация? Когда нужна денормализация?
- 15. Что такое VIEW и зачем оно нужно?
- 16. Что такое self-join и когда его используют?
9. В каком порядке выполняется SQL-запрос?
Интервьюер проверяет: понимаешь ли ты, почему одни конструкции работают, а другие — нет.
Порядок написания и порядок выполнения — разные вещи:
Порядок выполнения:
FROM/JOIN— определить таблицы и связиWHERE— отфильтровать строкиGROUP BY— сгруппироватьHAVING— отфильтровать группыSELECT— выбрать столбцы и вычислить выраженияDISTINCT— убрать дубликатыORDER BY— отсортировать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 — ИИ-ассистент, который помогает на техническом собеседовании в реальном времени. Подсказывает ответы, пока ты общаешься с интервьюером.
- Зайди на sobesai.app и скачай приложение
- Запусти перед собеседованием
- Sobes AI слушает вопрос и подсказывает структурированный ответ
- Работает с SQL, базами данных и другими техническими темами
Это часть 2 из 3. ← Часть 1: Junior | Часть 3: Senior →
Готовитесь к собеседованию?
Sobes AI слушает вопросы интервьюера и генерирует ответы в реальном времени.
Скачать Sobes AI