Механизм управляемых блокировок. Перевод конфигурации на управляемые блокировки Добавить блокировку данных используемых при проведении документов

О пользе перехода на управляемые блокировки в 1С 8.3 было сказано не раз — это сильно повышает эффективность и производительность работы оборудования.

Если Вам необходим партнер для перевода конфигурации в управляемый режим блокировок, просто обратитесь к нам! Подробности — .

Сам по себе процесс не такой уж и трудный. Однако процесс достаточно тонкий. Переход на управляемый режим неквалифицированным специалистом может сделать еще хуже.

Ниже мы разберем методику перехода с режима автоматических блокировок на управляемые.

Вся методика умещается в 7 коротких пунктах:

Переключите в палитре свойств конфигурации режим блокировок — «Управляемый и автоматический»:

Получите 267 видеоуроков по 1С бесплатно:

Переключение объекта в управляемый режим

Необходимо начинать с самых «загруженных» документов. Переключите документ в режим блокировок «Управляемый»:

Перевод регистров в управляемый режим

Необходимо перевести ВСЕ регистры 1С (накопления, бухгалтерии, сведений, расчета), которые производят движения данным документом, в режим управляемых блокировок:

Найти все транзакции с этими объектами

Необходимо найти все транзакции с этими объектами метаданных. Как явные, так и не явные.

Явные — те, которые вызываются в коде с помощью метода «НачатьТранзакцию()».

НЕ явные — те, которые вызываются в обработчиках объектов — «ПриЗаписи», «ОбработкаПроведения» и т.д.

Корректировка программного кода в транзакция

Для явных транзакций необходимо передать в параметр метода «НачатьТранзакцию()» параметр «РежимУправленияБлокировкойДанных.Управляемый».

Для НЕ явных транзакций установить блокировки с помощью объекта системы «БлокировкаДанных».

Пример использования блокировки:

Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить(«РегистрНакопления.ТоварыНаСкладах»);
ЭлементБлокировки.УстановитьЗначение(«Качество», Справочники.Качество.НайтиПоКоду(«1»));
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.ИсточникДанных = ДокументОбъект.ВозвратнаяТара;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных(«Номенклатура», «Номенклатура»);
ЭлементБлокировки.ИспользоватьИзИсточникаДанных(«Склад», «Склад»);
Блокировка.Заблокировать();

Заменить конструкцию ДЛЯ ИЗМЕНЕНИЯ

Периодически приходиться разбираться в применении механизмов блокировок в тех или иных случаях для реализации различных задач. Хотя информации на эти темы достаточно много, она сильно разрознена и со временем начинает забываться тот ворох материала, который пришлось перелопатить. Приходится разбираться заново…

В итоге, появилась идея структурировать и кратко изложить суть различных режимов блокировок в 1С в целом и применительно к типовым конфигурациям. Надеюсь, это будет полезно.

И так, поехали…

Сперва напишу про уровни изоляции транзакций, кратко рассмотрю только те уровни, которые имеют отношение к данной статье.

Уровни изоляции транзакций

Read committed (чтение завершенных) - разрешено чтение данных в транзакции, изменения по которым были завершены всеми остальными транзакциями. По умолчанию используется для большинства баз данных.

Read committed Snapshot (версионирование данных) - разрешено чтение старой версии данных, изменения по которым не завершены другими транзакциями. Штатно поддерживается базами данных: Postgre SQL и Oracle . Начиная с версии платформы 1С 8.3 реализован для работы с базами данных: MSSQL .

Repeatable read (повторяемое чтение) - запрет на изменение записей в транзакции, которые уже были считаны ранее в рамках остальных транзакций.

По поводу изоляции транзакций пока все, далее хочется сказать пару слов про механизм разделения итогов в регистрах накопления.

Разделение итогов регистров накопления

Регистр накопления на уровне базы данных состоит из двух таблиц: Основная таблица и Таблица итогов. Во время записи в регистр (как по приходу так и по расходу) происходит запись данных в обе таблицы, в основную таблицу записываются непосредственно данные, в таблице итогов обновляется итоговая строка по набору измерений регистра. Соответственно, при работе параллельных транзакций запись в таблицу итогов по одному набору измерений не может быть выполнена одновременно, что понижает скорость проведения документов.

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

Для раскрытия основной темы статьи, мне потребуется описать общие принципы механизмов контроля остатков, которые применяются в типовых конфигурациях. Если коротко, существует старый и новый механизмы контроля, причем оба применяются на текущий момент, несмотря на то, что новому режиму уже около 8 лет.

Механизмы контроля остатков в типовых конфигурациях 1С

Старая схема, далее OLD - формируется запрос к базе данных для выполнения контроля свободных остатков, в случае положительного решения, формируется движение по регистру. На данный момент применяется в Бухгалтерии 3.0 и в некоторых алгоритмах УТ 11, КА 2, ЕРП 2.

Недостатки :

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

Новая схема, далее NEW - выполняется движение по регистру, затем проверяется наличие отрицательных остатков, в случае их наличия, операция откатывается. На данный момент применяется в УТ 11, КА 2, ЕРП 2.

Преимущества:

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

Недостатки :

  • в случае, если для выполнения проведения необходимо получать данные из регистров учета (например расчет себестоимости для списания), в любом случае необходимо блокировать записи уже в момент их прочтения.

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

Ну что, настало время перейти, собственно, к изложению основной темы даной статьи - описание режимов блокировок . На самом деле, режимов всего два: Автоматический и Управляемый , они указываются в общих свойствах конфигурации, уверен, что все это прекрасно знают, поэтому не останавливаюсь на этом подробно.

Вы уже наверно догадались, что работать с этими двумя режимами необходимо по разному применительно к разным механизмам проведения документов. Разберем это более подробно.

Режим автоматических блокировок

В данном случае используется описанный выше режим изоляции транзакций: Repeatable read .

Примечание: в данной статье рассматривается преимущественно клиент серверный вариант работы. Для файлового режима будет применяться еще более высокий уровень изоляции, который здесь рассматривать не будем.

Для исключения взаимоблокировок при проведении документов с контролем остатков - OLD применяется конструкция языка запросов «ДЛЯ ИЗМЕНЕНИЯ », позволяющая при первом чтении данных в транзакции наложить на эти данные не разделяемую блокировку на чтение, а блокировку обновления. Соответственно, в другой транзакции уже будет невозможно выполнить подобную процедуру, так как наложить на одни и те же данные две блокировки обновления из разных транзакций нельзя .

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

Примечание: В случае работы с файловой базой и с P postgre SQL , блокировка накладывается целиком на всю таблицу.

Пример:

ВЫБРАТЬ ОстаткиТоваров.Номенклатура, ОстаткиТоваров.КоличествоОстаток КАК Количество ИЗ РегистрНакопления.ОстаткиТоваров.Остатки КАК ОстаткиТоваров ДЛЯ ИЗМЕНЕНИЯ

Использовать режим контроля остатков - NEW совместно с автоматическим режимом блокировок имеет смысл только для регистров без разделения итогов, в этом случае, никаких дополнительных действий делать не нужно. При использовании регистров с разделением итогов может возникнуть d ea dlock на чтении данных, если запись в регистр производилась одновременно, и каким-то образом решить данную проблему не получится.

Режим управляемых блокировок

В данном случае, применяется режимы изоляции транзакций: Read committed и Read committed Snapshot .

OLD - разделяемая блокировка снимается после прочтения данных об остатках, поэтому, чтобы исключить возможность возникновения отрицательных остатков, необходимо выполнить блокировку необходимых записей в регистре явно до формирования запроса на получение остатков. Собственно, в этом и состоит принцип управляемого режима блокировок.

Пример:

БлокировкаДанных = Новый БлокировкаДанных; ЭлементБлокировки = БлокировкаДанных.Добавить("РегистрНакопления.ТоварыНаСкладах.НаборЗаписей"); ЭлементБлокировки.УстановитьЗначение("Склад", Склад); ЭлементБлокировки.УстановитьЗначение("Номенклатура", Номенклатура); ЭлементБлокировкиДанных.Режим = РежимБлокировкиДанных.Исключительный; БлокировкаДанных.Заблокировать();

Использование режима контроля остатков NEW :

В случае использования регистров без разделения итогов дополнительные блокировки к наложенными базой данных не нужны, СУБД сама заблокирует необходимые данные (в данном случае записи в таблице итогов регистра накопления).

В случае использования регистров накопления с разделением итогов (по умолчанию к конфигураторе создаются регистры именно с данным флагом) можно получить следующие негативные ситуации:

  • Без режима версионирования (MS SQL и 1С 8.2) - получим взаимоблокировку при попытке чтения данных, если запись в двух транзакциях была выполнена одновременно. При записи данных блокировка не будет возникать, так как используются разные строки СУБД (разделение итогов)
  • С режимом версионирования Snapshot (postgresql, oracle или 1С 8.3) - блокировка возникать не будет, но будут появляться отрицательные остатки, так как контроль будет выполнен без учета всех не завершенных транзакций.

Для исключения подобной ситуации необходимо перед записью в регистр установить флаг набора записей: БЛОКИРОВАТЬ ДЛЯ ИЗМЕНЕНИЯ . Данная конструкция дает команду при записи накладывать исключительную блокировку на записи таблицы остатков регистра без учета разделителя итогов, по своей сути, она просто напросто временно отключает разделение итогов для регистра накопления.

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

Пример:

НаборЗаписей. БлокироватьДляИзменения = Истина;

Надеюсь, данная статья была полезной, и после ее прочтения создается более целостное понимание работы платформы 1С при различных режимах блокировок, используя разные механизмы контроля остатков.

Если что-то упустил и в чем-то был не точен, буду руд увидеть это в комментариях к статье.

Отдельное огромное спасибо, если отметите статью звездочкой, так как не что так не мотивирует на написание новых статей, как Ваше одобрение J

При многопользовательском режиме работы в 1С блокировки данных являются необходимым механизмом. Именно они защищают от ситуаций, похожих на одновременную продажу двумя менеджерами одного и того же товара разным клиентам. В платформе 1С предусмотрено два вида блокировок – управляемый и автоматический. Первый из режимов блокировок в 1С является оптимальным для высоконагруженных систем с большим количеством пользователей. Рассмотрим его подробнее.

Особенности управляемого режима блокировок

В отличие от автоматического, управляемый режим позволяет системе 1С использовать собственный менеджер блокировок и применять менее жесткие правила СУБД. То есть встроенный механизм позволяет учитывать бизнес-логику приложения и более плавно и точно устанавливает ограничения на чтение и запись данных. Смена режима блокировок может дать существенный прирост производительности и позволит сократить количество ошибок блокировок транзакции. Происходит это за счет дополнительной проверки менеджером блокировок на соответствие ограничениям, установленным внутри системы перед тем, как передать запрос СУБД.

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

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

Еще одной распространенной проблемой блокировок в 1С является импорт документов. Многие разработчики используют достаточно простое решение – при загрузке не проводить документы, а только создавать. А после, с помощью простого механизма, провести все загруженные данные в многопоточном режиме по ключевым характеристикам – номенклатуре, партнерам или складам.

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

Переключение в управляемый режим

Несмотря на то, что ниже будет представлен полный алгоритм перехода на режим управляемых блокировок, выполнять его должен опытный специалист. Если не понимать принципов работы механизма блокировок в 1С и СУБД, то вряд ли получится правильно написать ограничения. Но это относиться к сложным конфигурациям. Для простых конфигураций начинающие разработчики могут успешно закончить процесс переключения режима и набраться опыта:

  • В первую очередь нужно изменить режим управления блокировкой данных для конфигурации. Для этого в конфигураторе откройте дерево конфигурации и в свойствах корневого элемента в разделе «Совместимость» измените режим. Выберите пункт «Автоматический и управляемый», чтобы не возникало ошибок до того, как все объекты будут переведены на новый режим;
  • Теперь настает очередь документов. Ведь именно с их помощью мы регистрируем все события, которые нужно контролировать. Начинать перевод на управляемые блокировки 1С нужно с самых загруженных документов. На вкладке «Прочее» указываем режим блокировок «Управляемый»;
  • Находим все регистры, связанные с уже обработанным документом и переводим их в управляемый режим по аналогичному документам методу;
  • Следующий этап включает в себя поиск и изменение всех транзакций с измененными объектами. Сюда входят и явные изменения, включающие ключевые слова «НачатьТранзакцию()», так и все обработчики документов и регистров, включающие транзакции;
НачатьТранзакцию() Для Каждого ДокументНаУдаление ИЗ СпискаДокументов Цикл ОбъектДокумента = ДокументНаУдаление.ПолучитьОбъект(); Попытка ОбъектДокумента.УстановитьПометкуУдаления(Истина); Исключение Отказ = Истина; ОтменитьТранзакцию(); Сообщить("Не удалось удалить документ " + ОбъектДокумента); Прервать; КонецПопытки; КонецЦикла; ЗафиксироватьТранзакцию();
  • Исключить оператор языка запросов «ДЛЯ ИЗМЕНЕНИЯ». Заменить его можно объектом «БлокировкаДанных» с необходимостью изменить запрос и алгоритм его вызова и обработки.

Последние два этапа являются наиболее сложными и требующими квалификации от разработчика, но именно они являются гарантами поддержания рабочего состояния учета в системе.

Система «1С:Предприятие» позволяет использовать два режима работы с базой данных: режим автоматических блокировок в транзакции и режим управляемых блокировок в транзакции.

Принципиальное отличие этих режимов заключается в следующем. Режим автоматических блокировок не требует от разработчика каких-либо действий по управлению блокировками в транзакции для того. Эти правила обеспечиваются платформой системы «1С:Предприятие» за счет использования определенных уровней изоляции транзакций в той или иной СУБД. Такой режим работы является наиболее простым для разработчика, однако в некоторых случаях (например, при интенсивной одновременной работе большого количества пользователей) используемый уровень изоляции транзакций в СУБД не может обеспечить достаточной параллельности работы, что проявляется в виде большого количества конфликтов блокировок при работе пользователей.

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

В сводном виде отличия при работе в режиме автоматических блокировок и в режиме управляемых блокировок приведены в следующей таблице:

Вид блокировки Уровень изоляции транзакций
Автоматические блокировки
Файловая БД Таблиц Serializable
MS SQL Server Записей
IBM DB2 Записей Repetable Read или Serializable
PostgreSQL Таблиц Serializable
Oracle Database Таблиц Serializable
Управляемые блокировки
Файловая БД Таблиц Serializable
MS SQL Server Записей Read Commited
IBM DB2 Записей Read Commited
PostgreSQL Записей Read Commited
Oracle Database Записей Read Commited

Установка режима блокировок в конфигурации
Конфигурация имеет свойство . Каждый прикладной объект конфигурации также имеет свойство Режим управления блокировкой данных.
Режим управления блокировкой данных для всей конфигурации в целом может быть установлен в значения Автоматический , Управляемый (установлено по умолчанию для новой конфигурации) и Автоматический и управляемый . Значения Автоматический и Управляемый означают, что соответствующий режим блокировки будет использоваться для всех объектов конфигурации, независимо от значений, установленных для каждого из объектов. Значение Автоматический и управляемый означает, что для конкретного объекта конфигурации будет использован тот режим, который указан в его свойстве Режим управления блокировкой данных : Автоматический или Управляемый .
Следует отметить, что режим управления блокировкой данных, указанный для объекта метаданных, устанавливается для тех транзакций, которые инициируются системой «1С:Предприятие» при работе с данными этого объекта (например, при модификации данных объекта).
Если же, например, операция записи объекта выполняется в транзакции, инициированной разработчиком (метод НачатьТранзакцию() ), то режим управления блокировкой данных будет определяться значением параметра Режим блокировок метода НачатьТранзакцию() , а не значением свойства объекта метаданных Режим управления блокировкой данных .
По умолчанию параметр Режим блокировок имеет значение РежимУправленияБлокировкойДанных.Автоматический , поэтому для
того, чтобы в явной транзакции использовать режим управляемых блокировок, следует указывать значение этого параметра
РежимУправленияБлокировкойДанных.Управляемый (устанавливать данный параметр имеет смысл, если для свойства конфигурации «Режим управления блокировкой данных» выбрано значение «Автоматический и Управляемый» ) .

Работа с управляемыми блокировками средствами встроенного языка
Для управления блокировками в транзакции предназначен объект встроенного языка БлокировкаДанных . Экземпляр этого объекта может быть создан с помощью конструктора и позволяет описать необходимые пространства блокировок и режимы блокировок. Для установки всех созданных блокировок используется метод Заблокировать() объекта БлокировкаДанных . Если этот метод выполняется в транзакции (явной или неявной), блокировки устанавливаются и при окончании транзакции будут сняты автоматически. Если метод Заблокировать() выполняется вне транзакции, то блокировки не будут установлены.

Условия задаются на равенство значения поля указанному значению или на вхождение значения поля в указанный диапазон.
Условия могут быть заданы двумя способами:

● с помощью явного указания имени поля и значения (метод УстановитьЗначение() объекта ЭлементБлокировкиДанных );
● с помощью указания источника данных, содержащего необходимые значения (свойство ИсточникДанных объекта ЭлементБлокировкиДанных ).

Для каждого элемента блокировки может быть задан один из двух режимов блокировки:

● разделяемый,
● исключительный.

Таблица совместимости управляемых блокировок выглядит следующим образом

Разделяемый режим блокировки подразумевает, что заблокированные данные не могут быть изменены другой транзакцией до окончания текущей транзакции.
Исключительный режим блокировки подразумевает, что заблокированные данные не могут быть изменены другой транзакцией до окончания текущей транзакции, а также не могут быть прочитаны другой транзакцией, устанавливающей разделяемую блокировку на эти данные.

Особенности работы в режиме «Автоматический и управляемый»

При работе в режиме управления блокировками Автоматический и управляемый следует учитывать две особенности:

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

Рассмотрим перечисленные особенности более подробно.
Первая особенность заключается в том, что даже если для транзакции используется автоматический режим управления блокировками, система установит дополнительно и соответствующие управляемые блокировки при записи данных в этой транзакции. Из этого следует, что транзакции, исполняющиеся в режиме управляемых блокировок, могут конфликтовать с транзакциями,
исполняющимися в режиме автоматического управления блокировками.
Вторая особенность заключается в том, что режим управления блокировками, указываемый для объекта метаданных в конфигурации или указываемый при начале транзакции в явном виде (как параметр метода НачатьТранзакцию() ), является лишь «желаемым» режимом. Фактический режим управления блокировками, в котором будет исполняться транзакция, зависит от того, является ли данный вызов начала транзакции первым, или к этому моменту уже начата другая транзакция в данной сессии системы «1С:Предприятие».
Например, если требуется управлять блокировками при записи наборов записей регистра, при проведении документа, то управляемый режим блокировок должен быть установлен как для самого регистра, так и для документа, поскольку запись наборов записей регистра будет выполняться в транзакции, открытой при записи документа.

Давайте рассмотрим, как выглядит типичная монопольная блокировка в 1С .

Для меня она выглядит примерно вот так – кто-то занял что-то для выполнения какого-то действия . Все остальные это действие сделать не могут, они ждут. Чтобы такие ситуации разруливать, нужно знать хотя бы какую-то базовую теорию – как минимум, нужно понимать , когда ставится блокировка, какая блокировка ставится и т.д.

Я думаю, вы прекрасно знаете, что в 1С есть два режима блокировок: автоматический и управляемый .

  • В автоматическом режиме все просто:
    • При любом чтении ставится S -блокировка .
    • А при любой записи ставится X -блокировка – причем, блокировки есть только на сервере СУБД , 1С никаких блокировок не ставит.
  • Гораздо больше интересен управляемый режим . Его главная особенность в том, что в 8.2 и в 8.3 блокировки работают по-разному .
    • Например, в 8.2 у вас любое чтение будет ставить S -блокировку . Причем, чтение – это не просто Запрос.Выполнить(), но и Ссылка.Реквизит, Ссылка.ПолучитьОбъект() и т.д.
    • А в 8.3 без режима совместимости уже блокировок на чтение не будет . Таким образом, 8.3 безусловно выигрывает в плане параллельности работы.
    • Ну а дальше начинается самое интересное – например, для конструкции НаборЗаписей.Прочитать() в управляемом режиме 8.2 у вас будет S-блокировка на сервере СУБД (это естественно). Но кроме этого также будет разделяемая блокировка на сервере 1С , причем это проявляется и в 8.2, и в 8.3 . И главная проблема в том, что эта разделяемая блокировка у вас будет длиться до конца транзакции – пока транзакция не закончится, данные будут блокированы.
      Поэтому рекомендация номер один – если набор записей вам нужен только для чтения, лучше использовать запрос, а не объектную модель. Тогда вы ничего блокировать не будете, а если и будете, то ненадолго.
    • Естественно, при любом изменении данных (запись, проведение, удаление) будет ставиться исключительная блокировка на сервере 1С и эксклюзивная на сервере СУБД .

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

Длительность блокировок в управляемом режиме

Самое главное при работе с блокировками – это помнить, что любая управляемая блокировка всегда будет держаться до конца транзакции , поэтому важно минимизировать ее длительность .

Когда у вас есть выбор, где ставить блокировку (в начале транзакции или в конце), лучше выбрать в конце, потому что в этом случае риск возникновения ожиданий будет гораздо меньше.

Что касается конструкции Запрос.Выполнить(), то если это 8.2, блокировка будет сниматься сразу после выполнения запроса, а если это 8.3 (либо в вашей СУБД MS SQL включен режим Read Committed Snapshot Isolation), тогда блокировки вообще не будет. Поэтому если у вас 8.2 или 8.3 в режиме совместимости с 8.2 , я вам всячески рекомендую включить режим Read Committed Snapshot Isolation – у вас в любом случае повысится параллельность работы.

Вот типичный пример: можно сначала поставить блокировку, выполнить какие-то расчеты и проверки (посмотреть, заполнен ли реквизит и т.д.) и только потом транзакцию закончить – тогда у вас время блокировки будет долгим. Но лучше, если есть такая возможность, поступить по-другому: сначала сделать всякие расчеты (проверку заполнения и пр.), а блокировку наложить уже в самом конце. Тогда у вас время блокировки будет меньше, и, соответственно, риск возникновения ожиданий также снизится. Поэтому старайтесь наложение явных управляемых блокировок или любую запись в базу данных делать как можно ближе к концу транзакции .

Наиболее частые причины блокировок

Запрос со сканом

Чаще всего ожидание на блокировке возникает в случае неоптимального запроса . Например, у вас есть пользователь Иванов, который в процессе проведения документа заблокировал несколько позиций номенклатуры – только то, что ему было нужно. И есть пользователь Петров, который выполнил в транзакции запрос со сканированием (Запрос.Выполнить()). И если при чтении этот запрос нарвется на номенклатуру, которая была заблокирована Ивановым, то в случае использования вами версии 8.2 (либо 8.3 в режиме совместимости с 8.2), он остановится и будет ждать по умолчанию 20 секунд. При этом пользователь Петров встанет в ожидание, что, ему, конечно, не понравится. Как решить эту ситуацию? Казалось бы, ответ очевиден – можно взять и переписать запрос так, чтобы он не читал лишних строк , тогда все будет замечательно.

А если этот запрос платформенный? Или этот запрос используется в типовой конфигурации, которую вы по очевидным причинам изменять не можете – что тогда делать? Какие есть варианты?

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

Еще один вариант – это включить режим версионирования для MS SQL Server . Сразу оговорюсь, что описанная ситуация возможна только в СУБД-блокировочнике, потому что если у вас СУБД-версионник, там этой ситуации быть не может. А если вы включаете Read Committed Snapshot Isolation, тогда у вас MS SQL начинает работать почти как версионник. И ваш запрос не будет блокировать строки .

В 1С нет «волшебной таблетки», но включение режима Read Committed Snapshot Isolation – ближайший аналог этой «волшебной таблетки» . Вы минимальными действиями сразу резко сможете снизить количество ожиданий в вашей базе. Для этого вам всего лишь нужно выполнить несколько строк приведенным на скриншоте скриптом в MS SQL сервере , и вы сразу получите очень хорошее повышение параллельности работы. Конечно, это имеет смысл только для управляемого режима блокировок в конфигурации 1С. Для автоматического режима включать на сервере СУБД режим RCSI смысла нет.

Отсутствие режима разделения регистров

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

Этот режим можно включить в конфигураторе в свойствах регистра на закладке «Прочее» – там есть галочка «Разрешить разделение итогов» . Когда вы создаете новый регистр накопления, эта галочка уже по умолчанию включена. Тем самым, разработчики намекают, что использовать эту возможность очень удобно, потому что она помогает писать в регистр параллельно, даже если данные у вас пересекаются.

Но здесь есть нюанс – если по этому регистру у вас используется контроль остатков, то этот способ вам никак не поможет, вам останется только ускорять время работы транзакции, чтобы блокировка была как можно короче. Но вообще включение разделителя итогов – классная возможность и я ее крайне рекомендую использовать. Особенно полезно ее включить для регистра бухгалтерии , потому что там контроля остатков практически никогда не бывает.

Перемещение границы последовательности при проведении

Если у вас используется последовательность, в которой сдвигается граница при проведении документов, то, скорее всего, у вас возникают ожидания на блокировках. Например, два документа, у которых измерение в последовательности совпадает, параллельно провестись не смогут – кто-то кого-то будет ждать.

Что тут можно сделать? Вы ставите свойство последовательности «Не перемещать автоматически» и делаете регламентное задание, которое в вечернее время у вас эту последовательность будет двигать . Вот такое простое решение – просто разбить по времени эти операции, тогда никаких ожиданий в течение дня уже не будет.

Длительные транзакции

Старайтесь делать максимально короткие транзакции:

  • Выносите всякие проверки и расчеты за пределы транзакции – любую запись, любое наложение блокировок надо делать в самом конце.
  • Ни в коем случае никаких диалоговых окон в транзакции делать не нужно, особенно, если используется толстый клиент. Мы сталкивались с такими случаями, что у бухгалтера при проведении документа выскакивало диалоговое окно с кнопками «Да» и «Нет». И пока она решит, что нажать, пока с кем-нибудь посоветуется, пока кому-то позвонит – у нее это окно будет висеть, и все это время транзакция будет активна, и, соответственно блокировка тоже будет активна – ее время будет очень долгим. Так делать не нужно.
  • Как можно еще ускорить время транзакции? Можно ускорить код , который там выполняется. Ускорить запросы , если вы это умеете делать. Это сразу даст резкий прирост производительности.
  • Еще один вариант – это ускорить запись в регистры . Как? Можно программным путем, а можно аппаратным. Например, если вы купили нормальные SSD-диски, то скорость записи у вас естественно вырастет – даже запросы станут выполняться быстрее. И, соответственно, время транзакции также уменьшится. Это не значит, что одним апгрейдом дисков можно решить проблему блокировок, но хотя бы можно сгладить этот эффект – он будет уже не так заметен.

Эскалация в многопоточном режиме

Я очень надеюсь, что многие из вас используют многопоточность для повышения производительности всяких загрузок, выгрузок, перепроведения документов, при свертке больших объемов данных. Это действительно мощная возможность, которая позволяет получить ускорение в несколько раз. Однажды мне необходимо было свернуть регистр, содержащий более 100 миллионов строк, причем, неактуальные остатки нужно было куда-то выгрузить, оставив в базе только некоторый актуальный промежуток времени. Я подумал и решил реализовать для этого случая многопоточную обработку. В результате у меня получилось, что эти потоки стали блокировать друг друга, хотя их данные вообще никак не пересекались (в каждом потоке были разные регистраторы) – тем не менее, возникало ожидание на блокировке.

Выяснилось, что в одном из потоков был большой, тяжелый документ, который приводил к эскалации. Эскалация – это когда блокировка накладывается не на какую-то строку в таблице, а сразу на всю таблицу . И в моем случае в одном из потоков как раз и происходила блокировка вообще всей таблицы.

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

Когда обычно в 1С возникает эскалация? Чаще всего это какая-то тяжелая операция – закрытие месяца, расчет себестоимости и пр. – когда у вас в одной гигантской транзакции начинает проводиться много документов, блокируется вся таблица и в это время никто работать не может – параллельность падает. Такие операции необходимо учитывать отдельно и проводить их в нерабочее время , потому что в параллельном режиме вы их обработать не сможете.

Ошибка платформы – блокировка при использовании разделителя области данных

В платформе есть несколько ошибок, которые приводят к излишним ожиданиям на блокировке. Например, есть ошибка, которая меня очень удивила. Ситуация следующая – мы собрали данные об ожиданиях и увидели, что строка Запрос.Выполнить() накладывает управляемую исключительную блокировку, чего в принципе быть не может и не должно. Когда мы это увидели, мы подумали, что инструмент «сбоит». Еще раз загрузили данные. Все перепроверили. Действительно, накладывает. Оказалось, что такая ошибка появилась в платформе 8.3.6. При чтении – неважно, Запрос.Выполнить() или Константа.Прочитать() – вообще при любом чтении – платформа накладывала управляемую исключительную (Х) блокировку на поле, которое является разделителем данных и параллельность сразу падала. Причем, блокировка была именно исключительной.

Вот такая платформенная ошибка.

К счастью для нас клиент, у которого эта проблема проявилась, вообще не использовал этот разделитель данных, поэтому мы просто у реквизита сняли признак того, что он является разделителем. И все, ошибка исчезла. Но исправлена она или нет, я до сих пор не знаю. Могу точно сказать, что в 1С про эту ошибку знают, но когда они ее исправят, мне, к сожалению, не известно. Поэтому будьте готовы, что у вас такое тоже может быть.

Ошибка платформы – скан индекса регистра расчета

Также мы часто сталкиваемся с ошибками платформы по работе с регистром расчета. С точки зрения производительности у него вообще проблем очень много, потому что регистр расчета – это единственный объект в 1С, который не имеет кластерного индекса . Поэтому, когда вы записываете в регистр расчета несколько сотен строк (если строк мало, то эта ошибка не воспроизводится), или чистите там движения (записываете туда пустой набор движений) – будет производиться скан индекса таблицы регистра расчета . А поскольку это запрос платформенный, вы его поправить никак не сможете, и, так как это – удаление (накладывается X блокировка), то включение режима Read Committed Snapshot тоже никак не меняет ситуацию.

В итоге, методом проб и ошибок для этой проблемы было найдено решение. Поскольку у регистра расчета нет кластерного индекса (там есть только некластерный), пришлось этот некластерный индекс деактивировать и создать аналогичный, но кластерный. Все. После этого индекс стал использоваться, и все стало замечательно. Вот такой получился обход ситуации. И если у вас есть ЗУП, и вы сталкиваетесь с проблемой параллельности записи в регистр расчета, можете брать, пользоваться.

Еще одна проблема регистра расчета проявляется при чтении и заключается в том, что платформенный запрос, который читает данные из регистра расчета, тоже сканирует индекс. Но здесь уже помогает именно включение либо Read Committed Snapshot, либо, если у вас 8.3, вы можете убрать режим совместимости с 8.2, тогда этой проблемы у вас уже не будет.

Ошибка платформы – невозможность параллельной записи в периодический независимый регистр сведений

Очень старая ошибка, про которую в 1С тоже прекрасно знают, но, тем не менее, она до сих пор не исправлена – это невозможность параллельной записи в периодический независимый регистр сведений . Казалось бы, если у вас периоды разные (измерения совпадают, но периоды разные), вы могли бы записывать туда данные параллельно. Но этого не происходит, хотя должно бы быть. Потому что на сервере 1С накладывается излишняя блокировка по дате . На проектах эта ситуация встречается не часто – регистр сведений очень редко становится «узким местом» для блокировок. Обычно проблемы возникают из-за регистра накопления, либо из-за регистра бухгалтерии. Но, тем не менее, если вы с этим столкнетесь, можете попробовать сделать период измерением . Да, конечно, в этом случае никаких виртуальных таблиц (срез первых, срез последних) этот регистр сведений формировать уже не будет, но зато вы сможете спокойно писать в него параллельно, а запрос для получения среза первых/последних можно и самим формировать.

  • Во-первых, переходите на управляемый режим блокировок . Я думаю, это довольно очевидно, потому что если у вас используется автоматический режим, вы можете даже не удивляться вопросам «Почему у нас параллельность работы маленькая, почему много блокировок?» Сначала перейдите на управляемый режим, и, если после этого у вас проблемы останутся, тогда уже можно будет дальше разбираться.
  • Когда перевели конфигурацию в управляемый режим блокировок, обязательно должен быть включен режим СУБД Read Committed Snapshot Isolation . Это прямо Must Have –сразу будет резкий прирост по параллельности работы.
  • Используйте разделитель итогов для регистров . Там, где нет контроля остатков, обязательно нужно включить, чтобы не было ожиданий.
  • И НаборЗаписей.Прочитать() – старайтесь вообще для чтения не использовать , потому что при этом будет наложена управляемая блокировка, которая будет «висеть» до конца транзакции. Зачем вам это нужно? Читайте данные запросом, и блокировок тогда вообще не будет, если у вас 8.3 без режима совместимости или включен режим Read Committed Snapshot.
  • По поводу границы последовательности – тоже постарайтесь принять по умолчанию, что границу двигать только регламентным заданием в нерабочее время . При проведении не двигать.
  • Большие транзакции делить на несколько . Чем проводить миллион документов в одной транзакции, лучше сделать мелкие транзакции по 100 документов, по 1000 документов – еще лучше, если в многопоточном режиме. Это будет более стабильно.
  • Всякие расчеты, проверки и пр. делайте за пределами транзакции . Время транзакции должно быть минимальным, как можно меньше.

Пример решения проблемы блокировок

Как еще можно избавиться от излишних ожиданий?

Допустим, у вас есть торговые представители, которые после окончания рабочего дня (в 6 часов вечера), отправляют документы в базу. А там, как только эти документы через мобильный интернет приходят, они сразу пытаются загрузиться и провестись. В результате, если торговые представители заказали один и тот же товар с одного и того же склада, возникает ожидание, потому что они обращаются к одним и тем же данным, и поскольку там есть контроль остатков, разделитель итогов не поможет и кому-то кого-то придется ждать.

Как этого можно избежать? Можно при загрузке документы создавать, но не проводить , а потом написать механизм, который , например, реализует это дальнейшее проведение в многопоточном режиме , где каждый поток будет проводить документы по своему складу. Разнести, таким образом, эти процессы во времени: первый поток проводит документы по одному складу, второй поток – по второму складу и т.д. Тогда проблема будет решена.

Блокировки и оборудование

Как блокировки влияют на оборудование? Столкнувшись с проблемой блокировок, вы можете захотеть купить новый сервер. Конечно, можно попробовать, но корневым образом вы все равно ничего не измените. Да, транзакции станут быстрее, запросы станут быстрее. Но сама проблема с блокировками останется, потому что ее можно решить только на уровне кода .

Как влияет на оборудование оптимизация блокировок? Например, вы с автоматического режима перешли на управляемый, или взяли и включили Read Committed Snapshot. Пока система ждет , она оборудование не использует и оно у вас в этом случае простаивает . А как только у вас система заработала на полную мощность, ожиданий нет , у вас сразу идет резкий прирост, . И, в зависимости от того, в каком состоянии оно у вас на данный момент находится, это может быть критично. Например, если сервер у вас был загружен на 80%, а вы еще и блокировки свои устранили, он вообще может «лечь». Это обязательно нужно учитывать.

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

Инструмент для анализа блокировок

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