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

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

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

Диагностика узких мест: СУБД или текст запроса?

Когда проведение документа занимает длительное время (например, 45 секунд), в первую очередь выясним, где именно расходуются ресурсы. Для этого разберем основные шаги анализа:

  1. Замер производительности в 1С: С помощью встроенного замера производительности или Центра управления производительностью (ЦУП) определяем модуль и конкретный запрос, на который тратится максимальное время. Зачастую это запрос списания партий в процедуре движения по регистрам.
  2. Анализ счетчиков и ожиданий СУБД: С помощью системного монитора и трассировок оцениваем характер нагрузки. Огромное количество логических чтений (более миллиона за один вызов) при низкой нагрузке на процессор указывает на неоптимальный план выполнения, а не на аппаратные проблемы дисковой подсистемы.
  3. Оценка дисковой очереди и задержек: Кратковременный рост очереди к диску во время выполнения одного неоптимального запроса — это следствие перебора миллионов страниц в оперативной памяти и сброса промежуточных данных. Замена дисков на быстрые SSD без исправления запроса дает минимальный прирост (например, сокращение времени с 15 до 14.5 секунд), так как корень проблемы лежит в алгоритме выборки.
  4. Анализ плана выполнения (Execution Plan): Исследуем план запроса в СУБД. Наличие множественных вложенных циклов (Nested Loops) при соединении виртуальных таблиц с подзапросами приводит к тому, что внутренний запрос многократно пересчитывается для каждой строки внешней выборки.

Оптимизация запроса: перенос виртуальных таблиц во временные

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

Рассмотрим, как преобразовать неоптимальный запрос с помощью объекта МенеджерВременныхТаблиц:

  1. Выгружаем список списываемой номенклатуры, характеристик и складов документа в первую временную таблицу с обязательной индексацией по полям связи.
  2. Получаем остатки из виртуальной таблицы регистра партий, передавая фильтр по списку номенклатуры строго в параметры виртуальной таблицы, и помещаем результат во вторую временную таблицу.
  3. Индексируем временные таблицы по полям, участвующим в последующем соединении (Номенклатура, ХарактеристикаНоменклатуры, Склад, Партия).
  4. В основном запросе связываем физические временные таблицы. Это позволяет оптимизатору СУБД построить эффективный план (например, с использованием Hash Match или Merge Join вместо тяжелых вложенных циклов).

Посмотрим на пример правильной структуры пакетного запроса:


Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст = 
"ВЫБРАТЬ
|	ДокТовары.Номенклатура КАК Номенклатура,
|	ДокТовары.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
|	СУММА(ДокТовары.Количество) КАК Количество
|ПОМЕСТИТЬ ВТ_ТоварыДокумента
|ИЗ
|	&ТаблицаТовары КАК ДокТовары
|СГРУППИРОВАТЬ ПО
|	ДокТовары.Номенклатура,
|	ДокТовары.ХарактеристикаНоменклатуры
|ИНДЕКСИРОВАТЬ ПО
|	Номенклатура,
|	ХарактеристикаНоменклатуры;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|	ПартииОстатки.Номенклатура КАК Номенклатура,
|	ПартииОстатки.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
|	ПартииОстатки.ДокументОприходования КАК Партия,
|	ПартииОстатки.КоличествоОстаток КАК КоличествоОстаток,
|	ПартииОстатки.СтоимостьОстаток КАК СтоимостьОстаток
|ПОМЕСТИТЬ ВТ_ОстаткиПартий
|ИЗ
|	РегистрНакопления.ПартииТоваровНаСкладах.Остатки(
|			&МоментВремени,
|			Номенклатура В (ВЫБРАТЬ ВТ.Номенклатура ИЗ ВТ_ТоварыДокумента КАК ВТ)) КАК ПартииОстатки
|ИНДЕКСИРОВАТЬ ПО
|	Номенклатура,
|	ХарактеристикаНоменклатуры;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|	Товары.Номенклатура КАК Номенклатура,
|	Товары.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
|	Товары.Количество КАК КоличествоКВписанию,
|	Партии.Партия КАК Партия,
|	ЕСТЬNULL(Партии.КоличествоОстаток, 0) КАК КоличествоОстаток,
|	ЕСТЬNULL(Партии.СтоимостьОстаток, 0) КАК СтоимостьОстаток
|ИЗ
|	ВТ_ТоварыДокумента КАК Товары
|	ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ОстаткиПартий КАК Партии
|		ПО Товары.Номенклатура = Партии.Номенклатура
|		И Товары.ХарактеристикаНоменклатуры = Партии.ХарактеристикаНоменклатуры
|УПОРЯДОЧИТЬ ПО
|	Товары.Номенклатура,
|	Партии.Партия.МоментВремени ВОЗР";

Такой подход сокращает количество логических чтений с миллионов до нескольких тысяч и ускоряет выполнение конкретного запроса в 10–15 раз (в реальных условиях — с 15 секунд до 1 секунды).

Внедрение механизма отложенного проведения

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

  1. Оперативное проведение по количественному учету: В момент нажатия кнопки «Провести» формируются движения только по регистрам остатков товаров на складах и взаиморасчетов. Это занимает доли секунды и не блокирует работу пользователей.
  2. Регламентное списание партий: Формирование движений по партионному учету и расчет себестоимости выносятся в фоновое задание через объект РегламентныеЗадания или типовую обработку «Проведение по партиям», которая запускается с периодичностью в несколько минут или в ночное время.

Рекомендации по обслуживанию базы данных и регистров

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

  1. Актуализация границы итогов: Проверяем дату рассчитанных итогов по регистрам накопления через пункт меню управления итогами. Если граница отстает, получение виртуальной таблицы остатков на текущую дату вынуждает платформу считывать все движения от старой точки итогов, создавая колоссальную нагрузку на дисковую подсистему.
  2. Регулярный пересчет статистики: Настраиваем ночное регламентное обслуживание в СУБД с обновлением статистики таблиц базы данных для предотвращения ошибок оптимизатора при построении планов.
  3. Настройка системной базы tempdb: Разделяем файлы данных базы tempdb на несколько одинаковых файлов (по числу физических ядер процессора, но не более 8), чтобы исключить очереди распределения страниц при интенсивной работе с временными таблицами.
← На главную