Каждый специалист по автоматизации торговли рано или поздно сталкивается с ситуацией, когда пользователи начинают жаловаться на скорость работы интерфейса. Одной из самых частых «болевых точек» в конфигурации 1С:Управление торговлей (начиная с версии 11) является форма подбора товаров в документы продажи. Система может открывать форму подбора по 15–20 секунд, зависать при переходе между папками и «спотыкаться» при обычной прокрутке списка номенклатуры.
В этой статье мы подробно разберем, почему возникает эта проблема, как она связана с архитектурными особенностями платформы 1С:Предприятие 8.3 и механизмами СУБД, а также рассмотрим практические способы ее решения как для администраторов, так и для разработчиков.
Давайте проанализируем, что происходит на системном уровне, когда пользователь открывает форму подбора товаров (например, из документа Заказ клиента или Реализация товаров и услуг). Основу этой формы составляет динамический список (объект ДинамическийСписок), который выводит перечень номенклатуры. Для удобства менеджеров в этом списке отображаются не только наименования товаров, но и их актуальные цены.
Чтобы вывести цену, запрос динамического списка выполняет левое соединение (LEFT JOIN) основной таблицы справочника Номенклатура с виртуальной таблицей среза последних регистра сведений ЦеныНоменклатуры:
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ...)
Именно в параметре &Период и кроется главная разгадка производительности системы:
&Период дату этого документа. В этот момент СУБД больше не может использовать таблицу предрассчитанных итогов. Ей приходится «на лету» вычислять срез последних для каждой позиции номенклатуры, сопоставляя исторические записи в регистре.При большом объеме записей в регистре ЦеныНоменклатуры (сотни тысяч или миллионы строк истории) планировщик СУБД (будь то Microsoft SQL Server или PostgreSQL) строит крайне неоптимальный план запроса. Вместо быстрого поиска по индексам (Index Seek) СУБД переходит к полному сканированию таблиц (Table Scan / Index Scan). Как результат — система намертво зависает при каждой активизации строки, прокрутке или переходе по группам иерархии номенклатуры.
Выясним причину медленной работы с помощью последовательной диагностики. Если вы столкнулись с подобным поведением системы, рекомендуем выполнить следующие шаги.
Шаг 1. Замер производительности
Запустите конфигуратор, откройте базу в режиме отладки и включите замер производительности. Выполните переход по папкам в форме подбора. Вы увидите, что код отрабатывает практически мгновенно, но интерфейс продолжает «висеть» еще несколько секунд после завершения процедур. Например, процедура:
&НаКлиенте
Процедура ИерархияНоменклатурыПриАктивизацииСтрокиОбработчикОжидания()
ПодборТоваровКлиент.ОбработчикАктивизацииСтрокиИерархииНоменклатуры(ЭтаФорма);
КонецПроцедуры
Она завершается мгновенно, но платформа визуально замирает. Это первый признак того, что время уходит на получение данных СУБД для динамического списка при отображении интерфейса на клиенте.
Шаг 2. Проверка гипотезы с регистром цен
Чтобы убедиться, что дело именно в ценах, проверьте даты записей в регистре цен. Запустите в консоли запросов следующий простой запрос:
ВЫБРАТЬ
МИНИМУМ(ЦеныНоменклатуры.Период) КАК МинДата,
МАКСИМУМ(ЦеныНоменклатуры.Период) КАК МаксДата
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
Проанализируйте полученные периоды. Сравните дату документа, в котором тормозит подбор, с датой последней установки цен. Если дата документа меньше даты последних записей в регистре цен, то гипотеза подтверждается.
Рассмотрим несколько вариантов решения проблемы: от простых пользовательских настроек до изменения логики работы конфигурации разработчиком.
Если тормоза возникают из-за того, что пользователи работают со старыми документами («задним числом»), самым простым решением будет изменение бизнес-процесса:
В форме подбора УТ 11 присутствует информационная панель, которая при активизации каждой строки отправляет фоновые запросы для отображения цен по типам номенклатуры и остатков по складам.
Попросите пользователей свернуть эту панель (нажав на кнопку сворачивания группы или соответствующий крестик интерфейса). В свернутом состоянии эти тяжелые запросы перестают инициироваться платформой, что существенно увеличивает плавность прокрутки списка номенклатуры.
Если ваша база данных ведется на протяжении многих лет, регистр ЦеныНоменклатуры хранит колоссальный объем избыточной исторической информации. СУБД тяжело рассчитывать срез последних, пробираясь через миллионы неактуальных записей.
Рекомендуется выполнить свертку регистра цен номенклатуры:
Если конфигурация находится на поддержке с возможностью изменения (или вы используете механизм расширений), вы можете кардинально решить проблему на уровне кода.
Разберем, как оптимизировать запрос формы подбора. Откройте форму подбора номенклатуры и найдите динамический список. По умолчанию в его запросе используется левое соединение с виртуальной таблицей среза последних. Мы можем переписать логику получения цен одним из следующих способов:
ПриПолученииДанныхНаСервере (или реализовать получение цен через временные таблицы в динамическом списке, оптимизировав отборы).&Период значение Неопределено (или пустую дату). Это заставит СУБД всегда обращаться к предрассчитанной таблице итогов среза последних, минуя сложные расчеты на лету.Пример оптимизированного запроса динамического списка (упрощенная схема без соединения с виртуальной таблицей):
ВЫБРАТЬ
СправочникНоменклатура.Ссылка КАК Ссылка,
СправочникНоменклатура.Код КАК Код,
СправочникНоменклатура.Наименование КАК Наименование,
СправочникНоменклатура.ЭтоГруппа КАК ЭтоГруппа
ИЗ
Справочник.Номенклатура КАК СправочникНоменклатура
ГДЕ
НЕ СправочникНоменклатура.ПометкаУдаления
Такой список будет работать максимально быстро при любой иерархии и прокрутке, а цены для текущих видимых строк можно подтягивать программно в сопредельные не связанные колонки интерфейса.
Если база работает под управлением СУБД PostgreSQL, оптимизатор запросов может некорректно строить планы соединения вложенных виртуальных таблиц. Для исправления этой ситуации в конфигурационном файле postgresql.conf рекомендуется скорректировать следующие параметры:
join_collapse_limit в значение 8 (или ниже), чтобы предотвратить чрезмерное раздувание дерева соединений.work_mem (например, до 64MB или 128MB в зависимости от объема ОЗУ сервера).Эти настройки помогут планировщику PostgreSQL выбирать оптимальные индексные сканирования вместо тяжелых последовательных чтений всей таблицы цен.