Почему зависает запрос к СрезПоследних при групповом проведении документов на MS SQL и как это исправить

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

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

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

Анализ проблемы и симптомов

Типичная ситуация: в цикле проведения документа «Отчет о розничных продажах» выполняется запрос для получения цен из регистра сведений РегистрСведений.ЦеныАТТ:


ВЫБРАТЬ
	ЦеныПродажные.Склад КАК Склад,
	ЦеныПродажные.Номенклатура КАК Номенклатура,
	ЦеныПродажные.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
	ЦеныПродажные.Цена КАК Цена
ИЗ
	РегистрСведений.ЦеныАТТ.СрезПоследних(&Дата, Склад В (&СписокСкладов)
	   И Номенклатура В (&СписокНоменклатуры)) КАК ЦеныПродажные

Запрос выглядит простым, но при частом повторном вызове во время массового проведения документов сервер MS SQL перестает отвечать или выполняет данный шаг крайне долго. Выясним, почему это происходит именно на сервере.

Причины падения производительности на MS SQL Server

  1. Захват параметров оптимизатором (Parameter Sniffing): При первом выполнении запроса MS SQL Server формирует и кэширует план выполнения, ориентируясь на количество и состав переданных параметров (размер массива &СписокНоменклатуры). При последующих вызовах в цикле СУБД пытается использовать этот же план. Если количество позиций в документах различается, кэшированный план становится неэффективным — вместо быстрого поиска по индексу происходит полное сканирование таблицы (Index Scan или Table Scan).
  2. Различная обработка параметров платформой 1С: Если передаваемый в параметр массив содержит мало элементов, платформа 1С подставляет их прямо в текст запроса или передает параметрами хранимой процедуры. Если массив большой, платформа скрыто создает временные таблицы в TempDB с последующими операциями INSERT. Такая разница в поведении приводит к нестабильности планов выполнения MS SQL.
  3. Эскалация блокировок (Lock Escalation): При выполнении запросов к регистру сведений внутри транзакции проведения СУБД накладывает разделяемые блокировки (S-блокировки). Если сканируется большой объем строк, MS SQL эскалирует блокировки до уровня всей таблицы регистра, вызывая взаимные блокировки и зависания соседних процессов.
  4. Параллелизм (MAXDOP) и фрагментация индексов: Если параметр Max Degree of Parallelism на SQL-сервере больше 1, оптимизатор пытается распараллелить подзапрос получения среза последних. В условиях высокой нагрузки это приводит к ожиданиям типа CXPACKET. Высокая фрагментация физических индексов таблицы _InfoRg... дополнительно увеличивает нагрузку на дисковую подсистему.

Способы оптимизации кода 1С

Проанализируем решения, которые позволяют устранить зависание на уровне конфигурации 1С.

Вариант 1. Вынос запроса цен за пределы цикла проведения

Самое эффективное архитектурное решение при групповом проведении — отказаться от выполнения запросов к виртуальным таблицам внутри транзакции проведения каждого документа.

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

Вариант 2. Использование явной временной таблицы и составного отбора

Чтобы избежать непредсказуемого поведения платформы при передаче массивов в параметры, поместим список номенклатуры и складов во временную таблицу и проиндексируем её. Отбор в виртуальной таблице перепишем через составное условие (Склад, Номенклатура) В (...):


ВЫБРАТЬ
	вт.Склад КАК Склад,
	вт.Номенклатура КАК Номенклатура
ПОМЕСТИТЬ ВТ_Отбор
ИЗ
	&ТаблицаОтбора КАК вт;

ИНДЕКСИРОВАТЬ ПО
	Склад,
	Номенклатура;
;

ВЫБРАТЬ
	ЦеныПродажные.Склад КАК Склад,
	ЦеныПродажные.Номенклатура КАК Номенклатура,
	ЦеныПродажные.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
	ЦеныПродажные.Цена КАК Цена
ИЗ
	РегистрСведений.ЦеныАТТ.СрезПоследних(&Дата, (Склад, Номенклатура) В 
		(ВЫБРАТЬ ВТ_Отбор.Склад, ВТ_Отбор.Номенклатура ИЗ ВТ_Отбор КАК ВТ_Отбор)) КАК ЦеныПродажные

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

Вариант 3. Замена виртуальной таблицы прямым запросом к физической таблице

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

Оптимизация и обслуживание MS SQL Server

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

  1. Обновление статистики и обслуживание индексов: Регулярно выполняйте процедуры UPDATE STATISTICS с параметром FULLSCAN для таблиц регистров сведений, а также реорганизацию (REORGANIZE) или перестроение (REBUILD) индексов. Очистить кэш неэффективных планов выполнения можно командой DBCC FLUSHPROCINDB.
  2. Ограничение параллелизма (MAXDOP): В настройках сервера MS SQL Server рекомендуем установить параметр Max Degree of Parallelism равным 1 (или не более 2–4 для высоконагруженных систем). Это предотвратит зависания из-за разборки подзапросов на параллельные потоки.
  3. Включение режима RCSI (Read Committed Snapshot Isolation): Включение режима версионирования строк на уровне базы данных MS SQL предотвратит блокировки чтения при выполнении срезов последних во время записи транзакций:
    
    ALTER DATABASE [Имя_Базы] SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;
    
  4. Управляемый режим блокировок: В конфигураторе 1С установите для регистра сведений режим блокировок Управляемый, чтобы избежать избыточных разделяемых блокировок таблиц на уровне СУБД.
← На главную