Блокировки в базе данных: почему запросы зависают в очереди
Блокировка в базе данных — это когда один запрос временно занимает строку, таблицу или ресурс, и все остальные запросы, которым нужны те же данные, вынуждены ждать своей очереди. Если ожидание затягивается, сайт или приложение начинает «зависать», хотя сама база данных при этом никуда не падает — она просто честно стоит в очереди.
Почему база данных вообще блокирует данные?
Представьте очередь в кассу: пока один человек оплачивает покупку, следующий не может встать на его место и одновременно пробивать чек. База данных работает похоже: когда один запрос меняет строку — обновляет остаток на складе, списывает деньги со счёта, — она временно «закрывает» эту строку от других изменений. Это нужно, чтобы данные не испортились: без блокировок два одновременных запроса могли бы затереть изменения друг друга, и в итоге получилась бы каша вместо корректных цифр.
Блокировка и deadlock — это одно и то же?
Нет, это разные вещи. Обычная блокировка — это просто ожидание: один запрос подождёт, пока другой закончит, и спокойно продолжит работу. А deadlock (взаимная блокировка) — это тупик: запрос А ждёт, пока освободится ресурс, занятый запросом Б, а запрос Б в это же время ждёт ресурс, занятый запросом А. Оба ждут друг друга бесконечно, и без вмешательства извне ситуация сама не разрешится.
К счастью, современные базы данных умеют такие тупики распознавать автоматически. Система обнаруживает круговую зависимость и принудительно прерывает один из запросов с ошибкой, чтобы освободить остальных. Разработчику остаётся только правильно обработать эту ошибку в коде — например, повторить запрос ещё раз.
Как понять, что причина тормозов именно в блокировках?
Первый признак — запросы, которые обычно выполняются мгновенно, вдруг начинают висеть секундами, а нагрузка на процессор сервера при этом невысокая. Если база данных «ест» мало ресурсов, но отвечает медленно, — это почти всегда сигнал не о нехватке мощности, а об ожидании чужих блокировок.
Проверить догадку можно через встроенные системные представления базы данных, которые показывают активные сессии и то, чего именно они ждут. В таких отчётах видно, какой запрос держит блокировку, как долго он выполняется и кто стоит за ним в очереди. Это первое место, куда стоит заглянуть при жалобах на медленную работу под нагрузкой.
Какие блокировки встречаются чаще всего?
Условно их можно разделить на несколько типов:
- Блокировка строки — самая частая и самая безобидная, затрагивает только конкретную запись.
- Блокировка таблицы — встречается реже, но задевает сразу всех, кто работает с этой таблицей.
- Блокировка на уровне транзакции — возникает, когда одна транзакция держит открытыми сразу несколько изменений и не спешит их подтверждать.
- Блокировка на чтение и на запись — в одних базах данных чтение не мешает записи благодаря механизму многоверсионности, в других может приводить к ожиданию.
Кстати, интересный и хорошо проверяемый факт: в PostgreSQL, одной из самых популярных баз данных с открытым кодом, используется технология MVCC (многоверсионное управление конкурентным доступом). Благодаря ей читающие запросы почти никогда не блокируют пишущие и наоборот — каждый читатель видит свою «версию» данных на момент начала своего запроса, поэтому не нужно ждать, пока другой процесс закончит запись.
Клауд АйСи — цифровые сервисы для бизнеса в одном кабинете: 1С в облаке с ежедневными резервными копиями, конструктор сайтов, Умный онлайн-чат и проверка контрагентов.
Ваши данные под защитой. Есть бесплатные тарифы навсегда.
Что чаще всего вызывает избыточные блокировки?
Обычно виноваты не сами блокировки, а то, как с ними работает приложение. Есть несколько типичных причин:
- Долгие транзакции, которые открывают изменение и «забывают» его завершить, — например, ждут ответа от внешнего сервиса, не закрыв транзакцию.
- Отсутствие подходящих индексов: без индекса база данных вынуждена просматривать и блокировать больше строк, чем нужно.
- Массовые обновления больших объёмов данных одним запросом в часы пиковой нагрузки.
- Разный порядок изменения таблиц в разных частях кода — именно это чаще всего и приводит к deadlock.
Как снизить количество блокировок и ускорить работу?
Главный принцип — держать транзакции как можно короче. Всё, что не связано напрямую с изменением данных: обращения к внешним сервисам, сложные вычисления, отправку писем — стоит выносить за пределы транзакции. Чем быстрее транзакция подтверждается, тем быстрее освобождается блокировка и тем меньше очередь.
Второй важный шаг — грамотные индексы. Если запрос ищет и блокирует строки без индекса, он вынужден пройтись по всей таблице и попутно затронуть гораздо больше данных, чем требуется. С индексом база данных находит и блокирует ровно то, что нужно.
Третье — единый порядок обращения к таблицам во всём приложении. Если во всех частях кода сначала всегда обновляется таблица заказов, а потом таблица остатков (а не наоборот в разных местах), вероятность deadlock резко снижается.
Что делать, если deadlock всё равно случился?
Паниковать не нужно: это штатная ситуация, с которой база данных справляется сама, автоматически прерывая один из конфликтующих запросов. Задача разработчика — предусмотреть повтор такого запроса в коде приложения, чтобы пользователь просто не заметил секундной заминки. Если же deadlock повторяется регулярно, а не раз в несколько недель, — это сигнал пересмотреть логику работы с транзакциями и порядок изменения таблиц.
Как с этим помогает «Клауд АйСи»?
Диагностика блокировок требует доступа к системным журналам и метрикам сервера, а после переезда на новую инфраструктуру часто не хватает времени разбираться в этом самостоятельно. В «Клауд АйСи» база данных разворачивается на управляемых серверах с готовым мониторингом производительности, что упрощает поиск долгих транзакций и узких мест ещё до того, как они превратятся в заметные пользователю тормоза.
1С в облаке с резервным копированием
Зарегистрируйтесь и подключите облачную 1С — ежедневные бэкапы и обновления уже включены.
Частые вопросы
Блокировки — это признак того, что база данных сломана?
Нет, это нормальный и необходимый механизм защиты данных от одновременных конфликтующих изменений. Проблемой блокировки становятся только тогда, когда ожидание слишком долгое или регулярно возникает deadlock.
Может ли индекс полностью избавить от блокировок?
Полностью — нет, но правильный индекс сильно сокращает количество данных, которые запрос вынужден затронуть и заблокировать, а значит уменьшает и время ожидания для остальных запросов.
Почему в PostgreSQL чтение обычно не блокирует запись?
Благодаря механизму MVCC каждый читающий запрос видит свою версию данных на момент старта, поэтому ему не нужно ждать завершения параллельной записи.
Нужно ли что-то менять в коде приложения, если случился deadlock?
Да, стоит предусмотреть автоматический повтор запроса, который был прерван базой данных, чтобы пользователь не увидел ошибку и не заметил заминку.