Как перевести самописную базу 1С на управляемые блокировки без потери производительности?

Программист 1С v8.3 (Управляемые формы) Управленческий учет IT и автоматизация бизнеса
← На главную

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

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

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

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

При использовании смешанного режима в базе данных одновременно сосуществуют два принципиально разных уровня изоляции транзакций на стороне СУБД:

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

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

Обязательная настройка MS SQL Server: Включение версионирования строк

Просто переключить флаг в конфигураторе 1С недостаточно. Без настройки СУБД вы не получите ожидаемого прироста производительности. Чтобы читающие транзакции больше не блокировались пишущими, необходимо перевести MS SQL Server в режим работы с версиями строк (RCSI — Read Committed Snapshot Isolation).

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


ALTER DATABASE [Имя_Вашей_Базы_Данных] SET ALLOW_SNAPSHOT_ISOLATION ON;
ALTER DATABASE [Имя_Вашей_Базы_Данных] SET READ_COMMITTED_SNAPSHOT ON;

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

Важный нюанс: Включение RCSI существенно увеличивает нагрузку на дисковую подсистему, где расположена база tempdb. Перед переключением убедитесь, что файлы tempdb размещены на быстрых SSD- или NVMe-накопителях.

Анализ кода и скрытые логические аномалии

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

В автоматическом режиме СУБД защищала разработчика от аномалии «потерянного обновления» (Lost Update). В управляемом режиме эта защита исчезает. Проанализируем классический пример кода, который считывает настройки или счетчики:


Транзакция = Новый Транзакция;
Транзакция.Начать();

// Читаем текущую настройку или номер
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	НастройкиПродаж.ЗначениеНастройки
    |ИЗ
    |	РегистрСведений.НастройкиПродаж КАК НастройкиПродаж
    |ГДЕ
    |	НастройкиПродаж.Настройка = &Настройка";
Запрос.УстановитьПараметр("Настройка", Справочники.Настройки.СчетчикДокументов);
Результат = Запрос.Выполнить().Выгрузить();

// Производим вычисления в памяти и записываем обратно
НовоеЗначение = Результат[0].ЗначениеНастройки + 1;

Набор = РегистрыСведений.НастройкиПродаж.СоздатьНаборЗаписей();
Набор.Отбор.Настройка.Установить(Справочники.Настройки.СчетчикДокументов);
НоваяСтрока = Набор.Добавить();
НоваяСтрока.Настройка = Справочники.Настройки.СчетчикДокументов;
НоваяСтрока.ЗначениеНастройки = НовоеЗначение;
Набор.Записать();

Транзакция.Зафиксировать();

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

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


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

// Только после этого безопасно выполнять запрос и запись

Особенности объектного чтения и работы с наборами записей

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

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

Настройка итогов регистров и флаги трассировки СУБД

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

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

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

  1. При отключенной эскалации массовая запись данных (например, загрузка более 5000 строк в регистр одним документом) порождает огромное количество индивидуальных блокировок строк в памяти MS SQL.
  2. Если серверу СУБД не хватит выделенной оперативной памяти под блокировки (Lock Memory), произойдет аварийное завершение работы процесса SQL Server с ошибкой нехватки ресурсов.
  3. Вместо флага -t1211 безопаснее использовать флаг -t1224. Он также предотвращает преждевременную эскалацию блокировок таблиц, но разрешает её в крайнем случае, когда оперативная память СУБД подходит к концу.

Резюме и план действий

Подводя итог, сформулируем краткий чек-лист для успешного перевода вашей самописной базы на управляемые блокировки:

  1. Установите свойство конфигурации Режим управления блокировками данных в значение Управляемый. Не используйте смешанный режим на рабочей базе.
  2. Включите режим версионирования строк (RCSI) на СУБД MS SQL Server. Убедитесь, что база tempdb находится на быстрых накопителях.
  3. Проведите аудит кода на предмет «потерянных обновлений» (Lost Update). В местах, где происходит конкурентное чтение с последующей модификацией данных, добавьте программную установку исключительной блокировки с помощью объекта БлокировкаДанных.
  4. Для регистров накопления задействуйте механизм разделения итогов.
  5. Избегайте объектного чтения движений через НаборЗаписей.Прочитать() в транзакциях проведения, заменяя его обычными запросами.
← На главную