Перший раз — бо вивчив список питань напам'ять і не розумів, що стоїть за відповідями. Другий — бо підготувався з 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.

Третьої співбесіди я не боюся. Цього разу я, здається, нарешті розумію, а не пам'ятаю.