В высоконагруженных конфигурациях, таких как «Альфа-Авто», работа со списками номенклатуры часто становится узким местом. Пользователи жалуются на «подвисания» при поиске, прокрутке или просто при открытии формы. Основная причина — расчет остатков «на лету» внутри запроса динамического списка. Разберем детально, почему это происходит и как кардинально ускорить работу формы, используя программные методы оптимизации.
Проанализируем ситуацию, описанную автором темы. Поиск по подстроке (ввод текста в поле поиска) работает значительно медленнее, чем отбор по конкретному значению (Alt+F). Выясним причину такого поведения платформы 1С.
Когда мы используем Alt+F, платформа генерирует SQL-запрос с простым фильтром WHERE по индексированному полю (например, по ссылке или коду). SQL-сервер мгновенно находит нужные записи.
Однако при поиске по строке (полнотекстовый поиск или поиск по части слова) платформа анализирует все видимые колонки списка. Если в запросе динамического списка присутствует ЛЕВОЕ СОЕДИНЕНИЕ с виртуальной таблицей остатков, SQL-серверу приходится сначала выполнить это соединение для огромного количества записей справочника, рассчитать остатки, а уже затем применять фильтр LIKE %текст%. Это приводит к полному сканированию таблиц (Full Scan) и огромным задержкам, так как индексы перестают работать эффективно.
Если нам необходимо оставить остаток в основном запросе динамического списка (например, для возможности сортировки), но мы хотим исключить тормоза при поиске, мы можем программно запретить платформе использовать колонку остатка для поиска и условий. Рассмотрим, как это сделать в процедуре ПриСозданииНаСервере.
Посмотрим на пример кода, который ограничивает функционал поля динамического списка:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Находим поле в настройках компоновки данных динамического списка
ПолеОстаток = Список.КомпоновщикНастроек.Настройки.ДоступныеПоляВыбора.Элементы.Найти("Остаток");
Если ПолеОстаток <> Неопределено Тогда
// Запрещаем группировку по этому полю
ПолеОстаток.ОграничениеИспользования.Группировка = Истина;
// Запрещаем сортировку (порядок)
ПолеОстаток.ОграничениеИспользования.Порядок = Истина;
// Запрещаем использование в условиях (отборах и поиске)
ПолеОстаток.ОграничениеИспользования.Условие = Истина;
КонецЕсли;
КонецПроцедуры
Этот метод позволяет «спрятать» тяжелое расчетное поле от механизма поиска. Платформа больше не будет пытаться искать введенную пользователем строку в колонке «Остаток», что существенно снизит нагрузку на сервер БД.
Это самый эффективный и рекомендуемый метод для вывода расчетных данных в списках. Разберем по шагам его механику. Вместо того чтобы соединять справочник с регистрами в основном запросе списка (выбирая данные для тысяч записей), мы будем получать остатки только для тех 30–40 строк, которые фактически отображаются на экране пользователя.
Номенклатура.ПриПолученииДанныхНаСервере.Рассмотрим пример реализации этого метода:
&НаСервере
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)
// Получаем массив ссылок номенклатуры, которые сейчас видны на экране
МассивСсылок = Строки.ПолучитьКлючи();
// Одним запросом получаем остатки только по этим ссылкам
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Номенклатура КАК Номенклатура,
| Остатки.КоличествоОстаток КАК Остаток
|ИЗ
| РегистрНакопления.ОстаткиТоваровКомпании.Остатки(, Номенклатура В (&МассивСсылок)) КАК Остатки";
Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
РезультатЗапроса = Запрос.Выполнить().Выбрать();
// Заполняем данные в отображаемых строках
Пока РезультатЗапроса.Следующий() Цикл
СтруктураСтроки = Строки[РезультатЗапроса.Номенклатура];
// Указываем имя колонки, которую мы добавили на форму
СтруктураСтроки.Данные.Остаток = РезультатЗапроса.Остаток;
КонецЦикла;
КонецПроцедуры
Преимущество этого метода: Скорость работы списка становится практически мгновенной и не зависит от общего объема данных в регистре или справочнике. Мы запрашиваем ровно столько данных, сколько нужно пользователю в данный момент.
Важный нюанс: Помните, что при таком подходе по колонке «Остаток» нельзя будет сделать стандартную сортировку или отбор через платформенный механизм, так как данных нет в основной выборке ДинамическогоСписка.
Выясним, за что отвечает эта конструкция в запросе. Это расширение языка запросов для Системы компоновки данных (СКД). Фигурные скобки обозначают необязательное условие. Платформа использует это место для подстановки пользовательских настроек (отборов).
Символ .* (звездочка через точку) крайне важен: он сообщает платформе, что пользователь может накладывать отборы не только по самой ссылке, но и по любому реквизиту номенклатуры (например, Номенклатура.Артикул или Номенклатура.ВидНоменклатуры). Платформа старается «прокинуть» эти отборы внутрь виртуальных таблиц для оптимизации, но в сложных запросах с множеством соединений (как в «Альфа-Авто») это не всегда спасает от медленной работы.
Проанализируем еще несколько факторов, которые могут замедлять вывод списка:
1. Сложные RLS (Rights Level Security): При использовании ВЫБРАТЬ РАЗРЕШЕННЫЕ 1С добавляет к вашему SQL-запросу условия проверки прав доступа. В «Альфа-Авто» правила RLS могут быть очень тяжелыми. Проверьте скорость работы под пользователем с полными правами. Если тормоза исчезли — проблему нужно искать в оптимизации ролей доступа.
2. Основная таблица: Убедитесь, что в свойствах динамического списка указана «Основная таблица» (Справочник.Номенклатура). Это позволяет платформе использовать механизм «ленивой загрузки» и корректно строить индексы.
3. Индексация в регистре: Проверьте, является ли измерение Номенклатура индексированным в регистре остатков. Обычно это так, но при значительных доработках конфигурации индекс могли случайно отключить.
Подводя итог, можно сказать, что для формы списка номенклатуры в «Альфа-Авто» оптимальным решением является использование ПриПолученииДанныхНаСервере для вывода остатков и цен, а для всех остальных реквизитов — использование стандартного динамического списка с четко определенной основной таблицей.