Как быстрее всего массово изменить реквизит у большого количества документов в 1С?

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

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

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

---

Вариант 1. Прямой SQL-запрос к базе данных (Самый быстрый, но опасный метод)

Если ваша база данных работает на SQL-сервере (MS SQL, PostgreSQL и др.), самым быстрым техническим способом изменения реквизита является выполнение прямого SQL-запроса UPDATE. Вместо создания миллионов объектов в памяти 1С и генерации отдельных транзакций на запись, СУБД выполнит одну массовую операцию за секунды или минуты.

Рассмотрим пример простого SQL-запроса для СУБД MS SQL Server, изменяющего реквизит «Дата» у определенного вида документа:


-- Внимание! Перед выполнением запроса обязательно сделайте резервную копию базы данных!
UPDATE _Document300
SET _Date_Time = '2023-12-31 23:59:59'
WHERE _Date_Time < '2023-01-01 00:00:00'

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

  1. Проблема кэширования платформы 1С. Сервер приложений 1С активно кэширует данные объектов в оперативной памяти рабочих процессов rphost. При выполнении прямого запроса в СУБД сервер 1С не узнает об этих изменениях. Пользователи и фоновые задания будут продолжать видеть старые значения реквизитов, пока не произойдет автоматический сброс кэша или перезапуск службы сервера 1С.
  2. Нарушение планов обмена (РИБ). Прямой UPDATE в СУБД не регистрирует изменения объектов на планах обмена. Если ваша база данных обменивается информацией с другими узлами, измененные документы никогда не улетят в другие базы.
  3. Обход бизнес-логики и версионирования. При прямой записи не отрабатывают подписки на события, обработчики ПередЗаписью и ПриЗаписи. Также полностью игнорируется механизм версионирования объектов (БСП) — в истории изменений документов не останется и следа от вашей корректировки.

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

---

Вариант 2. Оптимизированная пакетная запись средствами 1С (Безопасный путь)

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

  1. Режим загрузки данных. Запись объектов должна выполняться строго с установленным свойством ОбменДанными.Загрузка = Истина. Это отключает выполнение прикладных проверок в модулях объектов, предотвращает проведение документов и значительно ускоряет физическую запись в СУБД.
  2. Разделение данных на порции. Запись каждого документа в отдельной транзакции создает колоссальные накладные расходы. Напротив, попытка записать все миллионы документов в одной транзакции приведет к эскалации блокировок (Lock Escalation) СУБД, заблокирует всю таблицу для пользователей и переполнит лог транзакций (файл .ldf). Оптимальный размер порции для одной транзакции составляет от 1 000 до 5 000 объектов.

Рассмотрим шаблон кода, реализующий порционную запись в транзакции:


Выборка = Документы.РеализацияТоваровУслуг.Выбрать();
НачатаТранзакция = Ложь;
Счетчик = 0;
Порция = 2000; // Оптимальный размер порции

Пока Выборка.Следующий() Цикл
    Если Не НачатаТранзакция Тогда
        НачатьТранзакцию();
        НачатаТранзакция = Истина;
    КонецЕсли;

    // Получаем объект документа для изменения
    ДокументОбъект = Выборка.ПолучитьОбъект();
    ДокументОбъект.Дата = НоваяДата;
    
    // Включаем режим обмена для ускорения записи
    ДокументОбъект.ОбменДанными.Загрузка = Истина;
    ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);

    Счетчик = Счетчик + 1;

    // Фиксируем транзакцию по достижении размера порции
    Если Счетчик % Порция = 0 Тогда
        ЗафиксироватьТранзакцию();
        НачатаТранзакция = Ложь;
    КонецЕсли;
КонецЦикла;

// Не забываем зафиксировать остаток
Если НачатаТранзакция Тогда
    ЗафиксироватьТранзакцию();
КонецЕсли;

---

Вариант 3. Современные платформенные возможности (Для версий 8.3.26 и выше)

Если вы работаете на современных версиях платформы 1С:Предприятие, вам доступны новые мощные механизмы, которые кардинально меняют подход к производительности массовых операций:

---

Вариант 4. Распараллеливание процессов через фоновые задания (БСП)

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

В БСП предусмотрена функция ДлительныеОперации.ВыполнитьПроцедуруВНесколькоПотоков(). Она автоматически разбивает массив документов (или список видов документов) на порции и распределяет их выполнение по фоновым заданиям.

Выясним, сколько фоновых заданий (потоков) целесообразно создавать. Практика показывает, что оптимальное количество потоков равно количеству логических ядер процессора на сервере приложений (минус 1-2 ядра, чтобы оставить вычислительные ресурсы для текущей работы других пользователей).

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


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

---

Резюме: какую стратегию выбрать?

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

  1. Если база не участвует в РИБ, отключено версионирование, пользователей в базе нет, а время на выполнение ограничено минутами — используйте прямой SQL-запрос с предварительной остановкой сервера 1С.
  2. Если важна безопасность данных и стабильность системы — используйте пакетную запись средствами 1С с транзакциями по 2000–5000 объектов и установленным флагом ОбменДанными.Загрузка = Истина.
  3. Для максимального ускорения штатного метода задействуйте многопоточность БСП и современные методы платформы, такие как ВыбратьПоСсылкам().
← На главную