Почему жутко тормозит запись в регистр бухгалтерии при проведении документов и как это исправить?

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

При работе с крупными базами данных на платформе 1С:Предприятие разработчики часто сталкиваются с проблемой резкого падения производительности при проведении тяжелых документов, таких как Расчет себестоимости выпуска (РСС) в УПП 1.3 или аналогичных механизмов в ERP. Особенно ярко это проявляется при попытке очистить старые движения и записать новые (например, наборы от 150 000 до 500 000 строк). Операция отмены проведения или перезаписи пустого набора может занимать часы, хотя раньше те же объемы обрабатывались за считанные минуты.

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

Причина 1. Особенности физической структуры таблиц регистра бухгалтерии

Регистр бухгалтерии спроектирован на уровне СУБД гораздо сложнее, чем обычные регистры накопления или сведений. На уровне MS SQL он состоит не из одной таблицы, а из целого ряда связанных сущностей:

Когда мы вызываем метод Записать() для набора записей, СУБД вынуждена выполнять каскадные операции INSERT и DELETE одновременно во всех этих таблицах, а также обновлять связанные с ними индексы. Если на счетах, по которым делаются движения, настроено много субконто (особенно имеющих составной тип данных), объем таблицы аналитики увеличивается экспоненциально. При очистке старых проводок СУБД тратит колоссальное время на поиск и каскадное удаление строк по внешним ключам в таблице _AccRgED.

Причина 2. Накопление изменений в планах обмена

Если для регистра бухгалтерии настроен обмен данными (даже если активных узлов немного), при записи набора записей платформа 1С пытается зарегистрировать изменения для каждого узла. Это приводит к массовой вставке записей в служебную таблицу регистрации изменений вида _AccRgChngRRef.

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


// Отключаем авторегистрацию изменений для оптимизации записи
Движения.Хозрасчетный.ОбменДанными.Получатели.АвтоЗапись = Ложь;

// Если логика системы позволяет не регистрировать движения вообще
Движения.Хозрасчетный.ОбменДанными.Загрузка = Истина;

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

Причина 3. Эскалация блокировок и запись набора порциями

При записи очень большого объема данных в одну транзакцию MS SQL Server автоматически производит эскалацию блокировок — вместо блокировки отдельных строк блокируется вся таблица регистра. Это вызывает колоссальные задержки и конфликты блокировок.

Для решения этой проблемы отлично подходит метод записи данных порциями. Давайте рассмотрим пример кода, который позволяет записывать движения пачками (например, по 5 000 строк). Это существенно снижает нагрузку на дисковую подсистему и предотвращает эскалацию блокировок:


Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Движение = Движения.Добавить();
    ЗаполнитьЗначенияСвойств(Движение, Выборка);
    
    // Записываем порциями по достижении лимита
    Если Движения.Количество() >= 5000 Тогда
        Движения.Записать(Ложь);
        // Важно: после записи методом Записать(Ложь) набор необходимо очистить в памяти, 
        // чтобы не накапливать оперативную память, либо использовать промежуточную выгрузку.
    КонецЕсли;
КонецЦикла;

Если Движения.Количество() > 0 Тогда
    Движения.Записать(Ложь);
EndIf;

Обратите внимание, что в типовых конфигурациях (например, в УПП 1.3) уже может быть заложена аналогичная константа или переменная, регулирующая размер набора (например, РазмерНабораПриЗаписиРегистровУчетаЗатрат со значением по умолчанию 1000). Проанализируйте ее значение в вашей системе.

Причина 4. Влияние режима разделения итогов и поля _splitter

Если в регистре бухгалтерии включен режим разделения итогов, СУБД создает в таблицах итогов служебное поле _splitter.

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

Причина 5. Устаревание статистики СУБД и неэффективность стандартного «ТИ»

Стандартное средство «Тестирование и исправление» (ТИ) в 1С выполняет лишь базовые операции обслуживания. При записи 150 000+ строк в одной транзакции статистика распределения данных в MS SQL мгновенно устаревает. Оптимизатор СУБД начинает строить неверные планы выполнения запросов (например, вместо быстрого поиска по индексу Index Seek начинает выполнять полное сканирование огромной таблицы Table Scan / Index Scan).

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


-- Пример SQL-запроса для обновления статистики по таблицам регистра бухгалтерии
UPDATE STATISTICS _AccRg640 WITH FULLSCAN, COLUMNS;
UPDATE STATISTICS _AccRgED640 WITH FULLSCAN, COLUMNS;

Замените имя таблицы на фактическое имя таблиц вашего регистра в SQL-базе (его можно узнать с помощью функции ПолучитьСтруктуруХраненияБазыДанных).

Причина 6. Влияние механизмов ограничения доступа (RLS)

Даже если в базе данных во время расчета себестоимости работает один пользователь, включенные механизмы RLS (Record Level Security) накладывают серьезный отпечаток на скорость записи. Платформа при вызове метода Записать() под обычным пользователем неявно генерирует тяжелые запросы с множественными соединениями (JOIN) к таблицам прав доступа.

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


УстановитьПривилегированныйРежим(Истина);
// Выполнение тяжелой записи набора
Движения.Хозрасчетный.Записать();
УстановитьПривилегированныйРежим(Ложь);

Причина 7. Проблема «битых» дат в регистре

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

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

Причина 8. Настройки дисковой подсистемы, лога транзакций и TempDB

Запись и удаление сотен тысяч строк в рамках одной транзакции генерируют гигантский объем информации в логе транзакций MS SQL Server (файл .ldf).

Проанализируйте следующие системные параметры:

  1. Модель восстановления: Если база работает в режиме FULL (Полная модель восстановления), лог транзакций мгновенно разрастается. Переведите базу на время тяжелых расчетов в модель восстановления SIMPLE (Простая).
  2. Автоувеличение файлов (Autogrow): Если автоувеличение файлов базы данных или лога настроено в процентах (например, по умолчанию 10%), СУБД будет регулярно замораживать транзакцию на время выделения нового места на диске. Установите фиксированный шаг автоувеличения в мегабайтах (например, по 512 МБ или 1024 МБ).
  3. Размещение TempDB: Как показывает практика, перенос базы данных tempdb на максимально быстрый RAM-диск или NVMe SSD существенно увеличивает общую скорость транзакций при записи больших наборов, так как именно в tempdb строятся временные таблицы и промежуточные расчеты СУБД.

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

← На главную