Транзакции и уровни изоляции: где ловят блокировки, дедлоки и фантомы
Коллеги, давайте разберем план выполнения. Транзакция нужна не «для галочки», а чтобы атомарно пережить сбой и не оставить данные в полурабочем состоянии. Но чем выше уровень изоляции, тем чаще система начинает платить за порядок блокировками и ожиданием.
Базовая схема простая:
— Read Committed: читает только зафиксированное, но допускает неповторяемые чтения.
— Repeatable Read: защищает уже прочитанное, но может раздувать конкуренцию за строки.
— Serializable: самый строгий режим, зато чаще всего именно он превращает нормальный поток запросов в очередь.
Схема простая, но дьявол кроется в статистике: один и тот же код на маленькой нагрузке живет спокойно, а в продакшене начинает ждать соседей.
Ошибку часто делают так: держат транзакцию открытой дольше, чем нужно — между SELECT, внешним API и бизнес-логикой. В продакшене так лучше не делать, и вот почему: растет время удержания блокировок, увеличивается шанс дедлока, а журнал и версионность получают лишнюю нагрузку. Золотое правило: внутри транзакции только чтение и запись данных, без «пойду еще проверю в сервисе».
Если нужна предсказуемость, сначала смотрим, где именно конфликтуют запросы: какие таблицы, какие индексы, какой порядок доступа. Потом сокращаем транзакцию, выравниваем порядок обновлений и только после этого трогаем изоляцию. Посмотрим, что тут с I/O в реальности: часто проблема не в «слабом» уровне, а в долгих сканах и плохих индексах.
Держите транзакции короткими, уровень изоляции подбирайте под инцидент, а не по вкусу команды.
Оптимизация производительности баз
@database_performance_tuning_arb
Транзакции и уровни изоляции: где ловят блокировки, дедлоки и фантомы
Этот пост опубликован в Telegram-канале Оптимизация производительности баз. Подписаться можно по ссылке: @database_performance_tuning_arb.