При оптимизации производительности информационных баз 1С разработчики нередко сталкиваются с ситуацией, когда конфигурация работает в управляемом режиме блокировок, но у отдельных нетиповых регистров накопления (оборотных или остаточных) в свойствах указан автоматический режим. Разберем, как платформа 1С обрабатывает такие сочетания, нужно ли вручную менять режим блокировки у оборотного регистра, как влияет механизм Read Committed Snapshot Isolation (RCSI) на СУБД и где искать причины медленного проведения документов, если замер производительности не показывает явных проблем.
Рассмотрим, как платформа 1С:Предприятие 8 управляет транзакционными блокировками при различных настройках конфигурации и отдельных объектов:
Включение версионирования строк на стороне MS SQL Server (READ_COMMITTED_SNAPSHOT) позволяет запросам на чтение данных не ожидать снятия блокировок записи и не блокировать читаемые таблицы. Однако здесь важно учитывать тонкости работы платформы:
Если в коде проведения документа выполняется контроль остатков по остаточным регистрам, платформа в управляемом режиме автоматически накладывает блокировки только на записываемые данные (набор записей с отбором по регистратору). На считываемые остатки платформа блокировку автоматически не ставит.
Если разработчик не наложит явную управляемую блокировку в коде через объект БлокировкаДанных, при включенном RCSI параллельные транзакции прочитают снимок данных на момент начала транзакции из базы tempdb. В результате обе транзакции посчитают, что остаток достаточен, и параллельно спишут товар, что приведет к возникновению отрицательных остатков.
Посмотрим на пример правильной установки управляемой блокировки перед проверкой остатков:
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ТоварыНаСкладах");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.ИсточникДанных = ТаблицаТоваров;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Склад", "Склад");
Блокировка.Заблокировать();
Если документ проводится медленно (например, 8 секунд) даже при отсутствии конкуренции пользователей, первопричина кроется не в конфликтах транзакционных блокировок. Проанализируем шаги для выявления истинного источника задержек:
WRITELOG)._AccumRg, вместо быстрого чтения итогов из таблицы _AccumRgT._ChangeRec) на множестве узлов обмена кратно увеличивает время фиксации транзакции.DBMSSQL (или DBPOSTGRS) с отбором по длительности duration > 100000 (от 100 мс), а также событий CALL и SCALL. Это позволит точно увидеть текст SQL-запросов и понять, сколько реального времени уходит на стороне сервера баз данных.