Первый раз — потому что выучил список вопросов наизусть и не понимал, что за ответами стоит. Второй — потому что подготовился с AI, а он красиво соврал. Личная и немного позорная история о том, какие вопросы по MySQL реально ловят на собеседовании в 2026-м — от PRIMARY KEY до EXPLAIN — и почему список правильных ответов не спасает ни разу.


Признаюсь сразу: я дважды заваливал одно и то же собеседование. Я дважды завалил собеседование по MySQL. Вот все вопросы, на которых меня подловили - 1Не потому что не готовился — готовился оба раза добросовестно. А потому что оба раза готовился не так.

Расскажу оба провала подробно, по вопросам, — потому что это, по сути, весь список того, что реально спрашивают про MySQL на джуна и мидла. Просто дорога к каждому пункту у меня была на редкость болезненной.

Раунд первый: я вызубрил список и сгорел на первом же «а почему»

План был простой и, как мне казалось, надёжный: нагуглить список вопросов, выучить формулировки, прийти и оттарабанить. Первые пять минут собеседования прошли отлично. Дальше начались уточнения.

PRIMARY KEY против UNIQUE. Тут я не подвёл: PRIMARY KEY гарантирует уникальность и не пускает NULL, UNIQUE тоже гарантирует уникальность, но NULL разрешает. В таблице один PRIMARY KEY и сколько угодно UNIQUE. Дальше интервьюер спросил: «а что InnoDB делает, если первичного ключа нет вообще?» — и вот тут я поплыл. Оказалось, InnoDB не разводит руками, а сама выбирает первый подходящий UNIQUE-индекс с NOT NULL, а если и такого нет — создаёт скрытый служебный идентификатор. Формулировку я знал, механику под ней — нет.

FOREIGN KEY. Спросили, что происходит при удалении родительской записи. Тут я неплохо перечислил варианты: CASCADE удаляет дочерние записи следом, RESTRICT блокирует операцию, SET NULL обнуляет внешний ключ. Заминка вышла на вопросе «а как у вас в проекте?» — и тут выяснилось, что я знаю теорию, но ни разу не задумывался, что часть команд намеренно переносит эту логику на уровень приложения, а не доверяет её базе.

CHAR против VARCHAR. Это тоже прошло гладко: CHAR — строка фиксированной длины, хранит ровно объявленное число байт, VARCHAR — переменной, хранит только нужное плюс один-два служебных байта. CHAR быстрее там, где длина и правда фиксирована — код страны, пол, — VARCHAR годится для всего остального.

DATETIME против TIMESTAMP. А вот тут я сел красиво. TIMESTAMP хранит секунды с 1970 года и сам конвертируется под часовой пояс клиента, но упирается в 2038 год. DATETIME хранит дату как есть, без привязки к поясу, и живёт вплоть до 9999-го. Я бодро ответил «просто разные форматы» — и получил закономерный вопрос, какой из них выбрать для системы, которая должна пережить 2038 год. Молчание было красноречивым.

Дальше пошёл JOIN — и тут я выдохнул слишком рано

JOIN я знал железно, поэтому расслабился — и зря, потому что именно расслабленность на этом вопросе и ловят.

INNER JOIN отдаёт только те строки, где нашлось совпадение в обеих таблицах. LEFT JOIN — все строки левой таблицы целиком, а там, где пары не нашлось, — NULL вместо значений из правой. Я это отбарабанил. А потом меня спросили: «что вернёт LEFT JOIN, если совпадений нет вообще ни одного?» Я честно ответил «пустой результат» — и был неправ. Результат будет, просто дырявый: все строки левой таблицы с NULL вместо правой. Классическая ловушка для тех, кто знает формулировку, но ни разу не проверял руками.

Дали живую задачку — найти студентов, которые не решили ни одной задачи:

SELECT students.*
FROM students
LEFT JOIN solved_tasks ON students.id = solved_tasks.student_id
WHERE solved_tasks.id IS NULL;

Написал за минуту — с этим справился. А вот на вопросе про CROSS JOIN снова затупил и сходу не смог объяснить, почему он опасен. CROSS JOIN — это декартово произведение: каждая строка первой таблицы со каждой строкой второй. Миллион записей здесь и миллион там без условия соединения — и я только что попросил базу построить триллион строк результата. По залу интервьюера, кажется, пробежала лёгкая тревога за судьбу продакшена.

GROUP BY и HAVING — здесь я героически наступил на собственные грабли

Спросили, почему нельзя просто взять и выбрать негруппированный столбец при GROUP BY. Я бодро выдал заученное «MySQL выберет любое значение из группы» — и это был устаревший ответ. С режимом ONLY_FULL_GROUP_BY, который включён по умолчанию с MySQL 5.7, такой запрос просто упадёт с ошибкой. Разрешено выбирать только сами столбцы группировки, агрегаты и функционально зависимые от них поля.

Дальше — задачка: вывести категории курсов, где средний рейтинг выше 4.5.

SELECT category, AVG(rating) as avg_rating
FROM courses
GROUP BY category
HAVING AVG(rating) > 4.5;

Я по инерции чуть не написал условие через WHERE — и вовремя себя одёрнул. WHERE фильтрует строки до группировки и понятия не имеет об AVG(rating), потому что на этом этапе группировки ещё не существует. HAVING фильтрует уже готовые группы. Перепутать их — стабильная классика первого собеседования.

Индексы — вот здесь всё и закончилось

Спросили, как устроен индекс. Ответил правильно: это B+дерево из отсортированных значений с указателем на строку, ускоряет чтение. Спросили: «а почему тогда не проиндексировать вообще все столбцы?» — и вот на этом простом вопросе я завис дольше всего. Пришлось признать вслух, что не думал об этом раньше: каждый INSERT и UPDATE обязан обновить все индексы таблицы, а не только сами данные, — за скорость чтения всегда платишь скоростью записи.

Про составной индекс и правило левого префикса я знал только формулировку. Индекс на (course_id, level) отработает для условия по course_id, отработает для course_id + level, но окажется бесполезен для одного level — потому что дерево отсортировано по первому столбцу, и искать по второму без него так же бессмысленно, как искать слово в бумажном словаре, зная только вторую букву. Я это произнёс — но когда попросили нарисовать дерево на бумаге, стало ясно, что я цитирую, а не понимаю.

Я дважды завалил собеседование по MySQL. Вот все вопросы, на которых меня подловили - 2

Добили функцией поверх колонки:

-- индекс не используется
WHERE DATE(created_at) = '2026-01-01'

-- индекс используется
WHERE created_at >= '2026-01-01' AND created_at < '2026-01-02'

MySQL сравнивает результат функции, а не хранящееся значение — а в индексе лежат сырые значения, не пересчитанные. Почему первый вариант не использует индекс, я объяснить не смог — просто запомнил как факт, без причины за ним.

Последним гвоздём стал EXPLAIN — план для запроса по прогрессу студентов:

idtabletypepossible_keyskeyrows
1student_progressALLNULLNULL100000

type = ALL — полное сканирование таблицы. possible_keys = NULL — подходящего индекса нет вообще. На ста тысячах строк это не «может быть проблема», это она и есть. Я это увидел, но не смог с ходу сказать, что делать дальше. Если совсем коротко: покрывающий индекс — это индекс, в который уже включены все столбцы, нужные запросу, поэтому MySQL читает только его и вообще не заглядывает в таблицу. Мне понадобилось три подсказки интервьюера, чтобы вспомнить это своими словами.

Отказ пришёл вежливый. Вывод я сделал грубый: список вопросов не равно понимание. Формулировки я знал все. Механику за ними — примерно наполовину.

Раунд второй: я подготовился с AI — и AI меня красиво подвёл

На второй заход я не повторял старую ошибку. Развернул локальный MySQL, погонял EXPLAIN руками, прочувствовал индексы не как определение, а как разницу в секундах на реальной таблице. С транзакциями и версиями решил не рисковать и уточнить всё у нейросети — благо, три секунды на ответ, зачем гуглить.

Про ACID нейросеть выдала гладкий текст, я его пересказал: атомарность — всё или ничего, целостность транзакции никто не переживёт наполовину; согласованность — данные после транзакции остаются в согласованном состоянии; изолированность — параллельные транзакции не мешают друг другу; долговечность — подтверждённые данные не теряются даже при сбое.

Пример на изолированность я придумал сам, и он неожиданно зашёл. Представь склад с одной последней единицей товара. Один процесс читает остаток и без подтверждённой изоляции видит чужие незакоммиченные изменения — например, что товар уже списан, хотя вторая транзакция ещё может откатиться. Это грязное чтение: прочитал то, что ещё не факт. Второй сценарий — неповторяющееся чтение: в рамках одной транзакции дважды прочитал остаток и получил два разных числа, потому что между чтениями другая транзакция успела закоммитить свои изменения.

Тут повезло: спросили уровень изоляции InnoDB по умолчанию, и я не полез в чат — вспомнил сам. REPEATABLE READ, в основе — MVCC (Multi-Version Concurrency Control), которая держит для транзакции согласованный снимок данных на всё её время. Добавил, что у PostgreSQL дефолт другой, READ COMMITTED, — и увидел, что это засчитали как плюс.

Про InnoDB и MyISAM тоже прошло гладко: MyISAM не умеет в транзакции и блокирует таблицу целиком, а не строку. В 2026-м выбирать её для нового проекта — как выбрать Java 8 для нового бэкенда: технически работает, а объяснить зачем — не получится.

Дальше — оптимизация. Про проблему N+1 рассказал без запинки: один запрос достаёт список пользователей, а затем для каждого — ещё один запрос отдельно, и вместо одного JOIN получаешь N+1 поход в базу. Диагностика — не по коду, а по логу: там видно однотипную пулемётную очередь мелких SELECT-ов вместо одного составного запроса. Про SELECT * тоже не подвёл: тянет все столбцы без разбора, а если есть покрывающий индекс — заставляет базу всё равно идти в таблицу за лишним, обнуляя весь смысл индекса. Про JOIN и подзапрос честно признал: в MySQL 8.4 оптимизатор часто сам приводит их к сопоставимым планам, и выбирать стоит по читаемости и по факту из EXPLAIN, а не по мифу «джойны всегда быстрее».

А потом добила версия MySQL.

Спросил у чата перед собеседованием: «какая версия MySQL сейчас актуальна для продакшена?» Ответ пришёл уверенный: MySQL 8.0, стабильная и проверенная. Я это записал, выучил и на собеседовании выдал с полной убеждённостью.

Интервьюер помолчал секунду и спросил: «в курсе, что 8.0 в апреле 2026-го дошла до конца поддержки?» Не в курсе. Актуальная линия — MySQL 8.4 LTS, поддержка от Oracle до 2032 года, рядом уже вышла MySQL 9.7 как новый LTS-релиз. Сказать «мы на 8.0» с уверенным видом в 2026-м — как заявить, что пишешь на Python 2: формально бывает, но звучит как явный сигнал, что стек годами не трогали. Я дважды завалил собеседование по MySQL. Вот все вопросы, на которых меня подловили - 3Заодно спросили про MySQL и PostgreSQL — тут я справился, у обеих в 2026-м разница на простых операциях невелика, MySQL по-прежнему силён в CRUD и нагрузках на чтение, PostgreSQL — в сложной аналитике. А вот вопрос про MariaDB меня добил окончательно: я на автомате назвал её «тем же самым MySQL, просто форк» — а по факту это самостоятельная СУБД, исторически совместимая на уровне многих запросов и протоколов, но давно разошедшаяся с MySQL достаточно, чтобы перед миграцией всё перепроверять отдельно.

Второй отказ. Обиднее первого — потому что я честно готовился, просто доверился ответу, который никто не проверил.

Что объединяет оба провала

Пересматривал оба собеседования и увидел одну и ту же ошибку в разной обёртке. В первый раз я скопировал в голову список ответов. Во второй — скопировал в голову список ответов, которые сгенерировала нейросеть. Разница в источнике, а не в подходе. И там, и там я не понимал, что стоит за фразами, которые произношу.

Вот тут и проходит та самая граница, о которой мы говорим постоянно. Вайб-подход — спросить у нейросети готовый ответ, вставить в голову, не перепроверив. AI-native подход — задать тот же вопрос, а потом развернуть локальную базу и убедиться руками, актуален ли ответ, прежде чем нести его на живой разговор. Сгенерировать правильный на вид SQL или гладкое определение сегодня может кто угодно — модель одна и та же у всех. А вот перепроверить и объяснить, почему это так, — уже нет. По данным PwC, разработчики, которые именно так и работают с AI — понимают, а не просто пересказывают, — зарабатывают минимум на 56% больше тех, кто ограничивается копипастой.

Собеседование, если разобраться, всегда спрашивает одно и то же: не «что ты помнишь», а «что ты понимаешь настолько, чтобы объяснить кому-то, кто задаёт неудобные уточнения». Список вопросов эту проверку не проходит. Проходит только руки, которые сами это трогали.

Что теперь

Третий заход я готовлю иначе — не список, а практика: разворачиваю базу, ломаю её сам, читаю EXPLAIN до и после каждого решения, и всё, что советует AI, перепроверяю на своей же таблице, прежде чем повторить вслух хоть слово.

Я дважды завалил собеседование по MySQL. Вот все вопросы, на которых меня подловили - 4

Если у тебя фундамента под SQL пока нет — не повторяй мой первый провал, начни сразу с рук, а не со списка. На интерактивном курсе SQL от JavaRush ты пишешь и разбираешь запросы с первого урока — и сама на своих ошибках нащупываешь, где встанет индекс, а где нет. А когда фундамент есть и хочется не повторить мой второй провал — научиться пользоваться нейросетью по-инженерному, а не превращать её в источник красиво поданной устаревшей информации, — с этого начинается JavaRush AI Native Developer.

Третьего собеседования я не боюсь. В этот раз я, кажется, наконец понимаю, а не помню.