При групповом проведении документов в клиент-серверном режиме работы 1С специалисты нередко сталкиваются с ситуацией, когда процесс проведения полностью зависает. При этом в файловом варианте той же базы данных групповая обработка отрабатывает корректно и без задержек. Проблема проявляется на запросах к виртуальной таблице СрезПоследних регистров сведений (например, при получении цен номенклатуры).
Рассмотрим подробно причины такого поведения системы, проанализируем механизм работы СУБД MS SQL Server и разберем практические способы устранения зависаний как на уровне кода 1С, так и на уровне настроек сервера баз данных.
Типичная ситуация: в цикле проведения документа «Отчет о розничных продажах» выполняется запрос для получения цен из регистра сведений РегистрСведений.ЦеныАТТ:
ВЫБРАТЬ
ЦеныПродажные.Склад КАК Склад,
ЦеныПродажные.Номенклатура КАК Номенклатура,
ЦеныПродажные.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
ЦеныПродажные.Цена КАК Цена
ИЗ
РегистрСведений.ЦеныАТТ.СрезПоследних(&Дата, Склад В (&СписокСкладов)
И Номенклатура В (&СписокНоменклатуры)) КАК ЦеныПродажные
Запрос выглядит простым, но при частом повторном вызове во время массового проведения документов сервер MS SQL перестает отвечать или выполняет данный шаг крайне долго. Выясним, почему это происходит именно на сервере.
&СписокНоменклатуры). При последующих вызовах в цикле СУБД пытается использовать этот же план. Если количество позиций в документах различается, кэшированный план становится неэффективным — вместо быстрого поиска по индексу происходит полное сканирование таблицы (Index Scan или Table Scan).INSERT. Такая разница в поведении приводит к нестабильности планов выполнения MS SQL.Max Degree of Parallelism на SQL-сервере больше 1, оптимизатор пытается распараллелить подзапрос получения среза последних. В условиях высокой нагрузки это приводит к ожиданиям типа CXPACKET. Высокая фрагментация физических индексов таблицы _InfoRg... дополнительно увеличивает нагрузку на дисковую подсистему.Проанализируем решения, которые позволяют устранить зависание на уровне конфигурации 1С.
Самое эффективное архитектурное решение при групповом проведении — отказаться от выполнения запросов к виртуальным таблицам внутри транзакции проведения каждого документа.
СрезПоследних на требуемую дату.Чтобы избежать непредсказуемого поведения платформы при передаче массивов в параметры, поместим список номенклатуры и складов во временную таблицу и проиндексируем её. Отбор в виртуальной таблице перепишем через составное условие (Склад, Номенклатура) В (...):
ВЫБРАТЬ
вт.Склад КАК Склад,
вт.Номенклатура КАК Номенклатура
ПОМЕСТИТЬ ВТ_Отбор
ИЗ
&ТаблицаОтбора КАК вт;
ИНДЕКСИРОВАТЬ ПО
Склад,
Номенклатура;
;
ВЫБРАТЬ
ЦеныПродажные.Склад КАК Склад,
ЦеныПродажные.Номенклатура КАК Номенклатура,
ЦеныПродажные.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
ЦеныПродажные.Цена КАК Цена
ИЗ
РегистрСведений.ЦеныАТТ.СрезПоследних(&Дата, (Склад, Номенклатура) В
(ВЫБРАТЬ ВТ_Отбор.Склад, ВТ_Отбор.Номенклатура ИЗ ВТ_Отбор КАК ВТ_Отбор)) КАК ЦеныПродажные
Такая конструкция преобразуется платформой и СУБД в коррелированный подзапрос по индексированным полям, что позволяет оптимизатору MS SQL построить стабильный и быстрый план выполнения.
Виртуальная таблица СрезПоследних формирует внутри сложный подзапрос с группировкой по максимальной дате. Если регистр большой, логику среза можно переписать явно через выборку из физической таблицы с отбором Период <= &Дата, соединяя результаты с временной таблицей отбора по совпадению полей и максимальному периоду.
Если изменения в коде конфигурации ограничены, необходимо выполнить администрирование СУБД:
UPDATE STATISTICS с параметром FULLSCAN для таблиц регистров сведений, а также реорганизацию (REORGANIZE) или перестроение (REBUILD) индексов. Очистить кэш неэффективных планов выполнения можно командой DBCC FLUSHPROCINDB.Max Degree of Parallelism равным 1 (или не более 2–4 для высоконагруженных систем). Это предотвратит зависания из-за разборки подзапросов на параллельные потоки.
ALTER DATABASE [Имя_Базы] SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;
Управляемый, чтобы избежать избыточных разделяемых блокировок таблиц на уровне СУБД.