Производительность БД

Блокировки в базе данных: почему запросы зависают в очереди

Блокировка в базе данных — это когда один запрос временно занимает строку, таблицу или ресурс, и все остальные запросы, которым нужны те же данные, вынуждены ждать своей очереди. Если ожидание затягивается, сайт или приложение начинает «зависать», хотя сама база данных при этом никуда не падает — она просто честно стоит в очереди.

Почему база данных вообще блокирует данные?

Представьте очередь в кассу: пока один человек оплачивает покупку, следующий не может встать на его место и одновременно пробивать чек. База данных работает похоже: когда один запрос меняет строку — обновляет остаток на складе, списывает деньги со счёта, — она временно «закрывает» эту строку от других изменений. Это нужно, чтобы данные не испортились: без блокировок два одновременных запроса могли бы затереть изменения друг друга, и в итоге получилась бы каша вместо корректных цифр.

Блокировка и deadlock — это одно и то же?

Нет, это разные вещи. Обычная блокировка — это просто ожидание: один запрос подождёт, пока другой закончит, и спокойно продолжит работу. А deadlock (взаимная блокировка) — это тупик: запрос А ждёт, пока освободится ресурс, занятый запросом Б, а запрос Б в это же время ждёт ресурс, занятый запросом А. Оба ждут друг друга бесконечно, и без вмешательства извне ситуация сама не разрешится.

К счастью, современные базы данных умеют такие тупики распознавать автоматически. Система обнаруживает круговую зависимость и принудительно прерывает один из запросов с ошибкой, чтобы освободить остальных. Разработчику остаётся только правильно обработать эту ошибку в коде — например, повторить запрос ещё раз.

Как понять, что причина тормозов именно в блокировках?

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

Проверить догадку можно через встроенные системные представления базы данных, которые показывают активные сессии и то, чего именно они ждут. В таких отчётах видно, какой запрос держит блокировку, как долго он выполняется и кто стоит за ним в очереди. Это первое место, куда стоит заглянуть при жалобах на медленную работу под нагрузкой.

Какие блокировки встречаются чаще всего?

Условно их можно разделить на несколько типов:

  • Блокировка строки — самая частая и самая безобидная, затрагивает только конкретную запись.
  • Блокировка таблицы — встречается реже, но задевает сразу всех, кто работает с этой таблицей.
  • Блокировка на уровне транзакции — возникает, когда одна транзакция держит открытыми сразу несколько изменений и не спешит их подтверждать.
  • Блокировка на чтение и на запись — в одних базах данных чтение не мешает записи благодаря механизму многоверсионности, в других может приводить к ожиданию.

Кстати, интересный и хорошо проверяемый факт: в PostgreSQL, одной из самых популярных баз данных с открытым кодом, используется технология MVCC (многоверсионное управление конкурентным доступом). Благодаря ей читающие запросы почти никогда не блокируют пишущие и наоборот — каждый читатель видит свою «версию» данных на момент начала своего запроса, поэтому не нужно ждать, пока другой процесс закончит запись.

Клауд АйСи — цифровые сервисы для бизнеса в одном кабинете: 1С в облаке с ежедневными резервными копиями, конструктор сайтов, Умный онлайн-чат и проверка контрагентов.
Ваши данные под защитой. Есть бесплатные тарифы навсегда.

Что чаще всего вызывает избыточные блокировки?

Обычно виноваты не сами блокировки, а то, как с ними работает приложение. Есть несколько типичных причин:

  • Долгие транзакции, которые открывают изменение и «забывают» его завершить, — например, ждут ответа от внешнего сервиса, не закрыв транзакцию.
  • Отсутствие подходящих индексов: без индекса база данных вынуждена просматривать и блокировать больше строк, чем нужно.
  • Массовые обновления больших объёмов данных одним запросом в часы пиковой нагрузки.
  • Разный порядок изменения таблиц в разных частях кода — именно это чаще всего и приводит к deadlock.

Как снизить количество блокировок и ускорить работу?

Главный принцип — держать транзакции как можно короче. Всё, что не связано напрямую с изменением данных: обращения к внешним сервисам, сложные вычисления, отправку писем — стоит выносить за пределы транзакции. Чем быстрее транзакция подтверждается, тем быстрее освобождается блокировка и тем меньше очередь.

Второй важный шаг — грамотные индексы. Если запрос ищет и блокирует строки без индекса, он вынужден пройтись по всей таблице и попутно затронуть гораздо больше данных, чем требуется. С индексом база данных находит и блокирует ровно то, что нужно.

Третье — единый порядок обращения к таблицам во всём приложении. Если во всех частях кода сначала всегда обновляется таблица заказов, а потом таблица остатков (а не наоборот в разных местах), вероятность deadlock резко снижается.

Что делать, если deadlock всё равно случился?

Паниковать не нужно: это штатная ситуация, с которой база данных справляется сама, автоматически прерывая один из конфликтующих запросов. Задача разработчика — предусмотреть повтор такого запроса в коде приложения, чтобы пользователь просто не заметил секундной заминки. Если же deadlock повторяется регулярно, а не раз в несколько недель, — это сигнал пересмотреть логику работы с транзакциями и порядок изменения таблиц.

Как с этим помогает «Клауд АйСи»?

Диагностика блокировок требует доступа к системным журналам и метрикам сервера, а после переезда на новую инфраструктуру часто не хватает времени разбираться в этом самостоятельно. В «Клауд АйСи» база данных разворачивается на управляемых серверах с готовым мониторингом производительности, что упрощает поиск долгих транзакций и узких мест ещё до того, как они превратятся в заметные пользователю тормоза.

1С в облаке с резервным копированием

Зарегистрируйтесь и подключите облачную 1С — ежедневные бэкапы и обновления уже включены.

Частые вопросы

Блокировки — это признак того, что база данных сломана?

Нет, это нормальный и необходимый механизм защиты данных от одновременных конфликтующих изменений. Проблемой блокировки становятся только тогда, когда ожидание слишком долгое или регулярно возникает deadlock.

Может ли индекс полностью избавить от блокировок?

Полностью — нет, но правильный индекс сильно сокращает количество данных, которые запрос вынужден затронуть и заблокировать, а значит уменьшает и время ожидания для остальных запросов.

Почему в PostgreSQL чтение обычно не блокирует запись?

Благодаря механизму MVCC каждый читающий запрос видит свою версию данных на момент старта, поэтому ему не нужно ждать завершения параллельной записи.

Нужно ли что-то менять в коде приложения, если случился deadlock?

Да, стоит предусмотреть автоматический повтор запроса, который был прерван базой данных, чтобы пользователь не увидел ошибку и не заметил заминку.