Оптимизация производительности баз
2 subscribers
Download Telegram
Транзакции и уровни изоляции: где ломается логика и начинается блокировка

Коллеги, давайте разберем план выполнения. Транзакция — это не магия «всё или ничего», а договор с СУБД: читаем, пишем и блокируем только в рамках выбранной изоляции.

— Read Committed спасает от грязных чтений, но не от неповторяемых: два одинаковых SELECT могут увидеть разное.
— Repeatable Read держит стабильные строки, но фантомы и конкуренция за диапазоны часто вылезают боком.
— Serializable дает самую жесткую семантику, но за нее платят ожиданием, дедлоками и падением пропускной способности.

Посмотрим, что тут с I/O в реальности: длинная транзакция — это не «аккуратнее», а больше удержанных версий, дольше живущие блокировки и грязный хвост для обслуживания. Если внутри есть сетевые вызовы, внешние API или тяжелая обработка, вы растягиваете блокировку там, где она вообще не нужна. В продакшене так лучше не делать, и вот почему: база не знает, что вы «почти закончили».

Золотое правило: сначала мониторинг, потом индексы. Смотрите на wait events, блокировки, дедлоки, время жизни транзакций и реальные точки конкуренции. Часто достаточно сократить область транзакции, вынести чтение наружу или разделить «проверить» и «изменить» на два коротких шага.

Схема простая, но дьявол кроется в статистике: выбирайте минимально достаточную изоляцию и держите транзакции короткими. Если нужен строгий порядок — фиксируйте его явно, а не надеждой на удачу.
Сложный SQL не тормозит сам по себе — его ломают планы, селективность и лишний I/O

Коллеги, давайте разберем план выполнения. У тяжёлого запроса обычно три источника боли: сканы там, где нужен seek; плохая оценка кардинальности; лишние сортировки и хэши на больших объёмах. Схема простая, но дьявол кроется в статистике.

Что проверять первым:
— совпадает ли порядок условий с индексом;
— нет ли функций по колонке в WHERE/JOIN;
— не тащите ли лишние поля в SELECT, если они не нужны;
— не превращает ли OR нормальный план в полный перебор.

Посмотрим, что тут с I/O в реальности: если план красивый, но читает слишком много страниц, оптимизация начинается не с «добавим индекс», а с сокращения входного набора. Фильтры выносят как можно раньше, тяжёлые JOIN'ы — после отсечения мусора, агрегации — только после уменьшения строк.

Ещё один частый провал — CTE и подзапросы, которые читаются как «логика», а исполняются как отдельные тяжёлые этапы. Иногда помогает разнести запрос на шаги с временной таблицей: да, это лишняя запись на диск, но она дешевле бесконечных пересчётов. В продакшене так лучше не делать, и вот почему: без замера можно просто перенести боль из CPU в I/O. ⚠️

Золотое правило: сначала мониторинг, потом индексы. Снимите план, фактическое число строк, чтения, блокировки; только потом меняйте текст запроса. Иначе вы лечите не причину, а форму симптома.


Если понравилось — посмотри @team_productivity_stack_arb