Блокування метаданих (metadata lock, MDL) захищає структуру таблиці: поки хтось працює з таблицею в транзакції, змінити її схему не можна. Будь-який запит до таблиці, навіть звичайний SELECT, бере спільне MDL і тримає його до кінця транзакції. ALTER TABLE потребує виключного MDL.
Класичний сценарій аварії:
-- сесія 1: хтось у консолі
START TRANSACTION;
SELECT * FROM orders LIMIT 1; -- MDL взято, транзакція не закрита
-- ... пішов на обід
-- сесія 2: деплой
ALTER TABLE orders ADD COLUMN note TEXT; -- чекає на MDL
-- сесії 3..N: звичайний трафік
SELECT * FROM orders WHERE id = 5; -- теж чекають!
Найнеприємніше - останній крок: ALTER стоїть у черзі за виключним блокуванням, і всі нові запити до таблиці стають у чергу за ним. Таблиця фактично недоступна, хоча сам ALTER навіть не почався. Пул з'єднань застосунку швидко вичерпується.
Звідки беруться довгі транзакції:
- відкрита транзакція в консолі чи GUI-клієнті з вимкненим автокомітом;
- воркер черги, що відкрив транзакцію й чекає на зовнішній API;
- довгий звіт чи дамп без
--single-transaction.
Як знайти винуватця:
SELECT * FROM sys.schema_table_lock_waits\G
-- хто чекає, хто блокує, і готова команда KILL для блокувальника
SELECT trx_mysql_thread_id, trx_started, trx_query
FROM information_schema.innodb_trx ORDER BY trx_started;
Як захистити деплой:
- задати короткий тайм-аут очікування для сесії міграцій. За замовчуванням
lock_wait_timeout- рік:
SET SESSION lock_wait_timeout = 5;
ALTER TABLE orders ADD COLUMN note TEXT; -- не дочекався за 5 с - помилка, а не простій
- повторювати міграцію кілька разів з паузою;
- перед міграцією перевіряти
innodb_trxна довгі транзакції; - обмежувати довжину транзакцій у застосунку й тайм-аут неактивних сесій (
wait_timeout).
Онлайн DDL не рятує: навіть ALGORITHM=INSTANT бере виключне MDL на коротку мить на початку й наприкінці - і так само може застрягти за довгою транзакцією.