При проведении документов в конфигурациях с партионным учетом (например, в «1С:Управление торговлей 10.3» или «1С:Управление производственным предприятием») разработчики часто сталкиваются с существенными задержками. Документ может проводиться десятки секунд, причем основная часть времени уходит на списание партий. Проанализируем, почему типовые запросы выполняются медленно, как локализовать узкое место и какими методами можно многократно ускорить проведение.
Когда проведение документа занимает длительное время (например, 45 секунд), в первую очередь выясним, где именно расходуются ресурсы. Для этого разберем основные шаги анализа:
Nested Loops) при соединении виртуальных таблиц с подзапросами приводит к тому, что внутренний запрос многократно пересчитывается для каждой строки внешней выборки.Главная причина деградации производительности в классических партионных механизмах — использование соединений с виртуальными таблицами остатков или вложенными подзапросами. СУБД не всегда может корректно оценить кардинальность таких выборок и выбирает неэффективную стратегию соединения.
Рассмотрим, как преобразовать неоптимальный запрос с помощью объекта МенеджерВременныхТаблиц:
Номенклатура, ХарактеристикаНоменклатуры, Склад, Партия).Hash Match или Merge Join вместо тяжелых вложенных циклов).Посмотрим на пример правильной структуры пакетного запроса:
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ
| ДокТовары.Номенклатура КАК Номенклатура,
| ДокТовары.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
| СУММА(ДокТовары.Количество) КАК Количество
|ПОМЕСТИТЬ ВТ_ТоварыДокумента
|ИЗ
| &ТаблицаТовары КАК ДокТовары
|СГРУППИРОВАТЬ ПО
| ДокТовары.Номенклатура,
| ДокТовары.ХарактеристикаНоменклатуры
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура,
| ХарактеристикаНоменклатуры;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ПартииОстатки.Номенклатура КАК Номенклатура,
| ПартииОстатки.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
| ПартииОстатки.ДокументОприходования КАК Партия,
| ПартииОстатки.КоличествоОстаток КАК КоличествоОстаток,
| ПартииОстатки.СтоимостьОстаток КАК СтоимостьОстаток
|ПОМЕСТИТЬ ВТ_ОстаткиПартий
|ИЗ
| РегистрНакопления.ПартииТоваровНаСкладах.Остатки(
| &МоментВремени,
| Номенклатура В (ВЫБРАТЬ ВТ.Номенклатура ИЗ ВТ_ТоварыДокумента КАК ВТ)) КАК ПартииОстатки
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура,
| ХарактеристикаНоменклатуры;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| Товары.Номенклатура КАК Номенклатура,
| Товары.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
| Товары.Количество КАК КоличествоКВписанию,
| Партии.Партия КАК Партия,
| ЕСТЬNULL(Партии.КоличествоОстаток, 0) КАК КоличествоОстаток,
| ЕСТЬNULL(Партии.СтоимостьОстаток, 0) КАК СтоимостьОстаток
|ИЗ
| ВТ_ТоварыДокумента КАК Товары
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ОстаткиПартий КАК Партии
| ПО Товары.Номенклатура = Партии.Номенклатура
| И Товары.ХарактеристикаНоменклатуры = Партии.ХарактеристикаНоменклатуры
|УПОРЯДОЧИТЬ ПО
| Товары.Номенклатура,
| Партии.Партия.МоментВремени ВОЗР";
Такой подход сокращает количество логических чтений с миллионов до нескольких тысяч и ускоряет выполнение конкретного запроса в 10–15 раз (в реальных условиях — с 15 секунд до 1 секунды).
Если специфика базы данных предполагает интенсивную выписку документов в течение дня, оптимальным архитектурным решением является разделение проведения на два этапа:
РегламентныеЗадания или типовую обработку «Проведение по партиям», которая запускается с периодичностью в несколько минут или в ночное время.Чтобы поддерживать высокую скорость работы партионных механизмов на уровне платформы и СУБД, выполним следующие регламентные действия:
tempdb: Разделяем файлы данных базы tempdb на несколько одинаковых файлов (по числу физических ядер процессора, но не более 8), чтобы исключить очереди распределения страниц при интенсивной работе с временными таблицами.