При работе с крупными информационными базами 1С:Предприятие разработчики часто сталкиваются с проблемой, когда при вводе данных или вставке скопированного значения (через Ctrl+V) в поле выбора система "зависает" на несколько секунд. Особенно остро эта проблема проявляется на справочниках с объемом данных более 1–2 миллионов записей, таких как «Серии номенклатуры», «Штрихкоды» или «Номенклатура».
В этой статье мы подробно разберем, почему стандартный платформенный механизм поиска начинает работать медленно, как устроены индексы СУБД для подчиненных справочников, и рассмотрим пошаговые методы оптимизации: от простых настроек в конфигураторе до написания эффективного кода в модуле менеджера.
Давайте проанализируем ситуацию на уровне СУБД. Когда пользователь вводит строку в поле выбора, платформа 1С автоматически генерирует и отправляет к базе данных SQL-запрос. В проблемных случаях этот запрос выглядит следующим образом:
SELECT TOP 10
T1._IDRRef,
T1._Code,
T1._Description
FROM
dbo._Reference130 T1
WHERE
T1._Code LIKE ? ESCAPE '\'
ORDER BY
T1._Code
Если в таблице справочника (например, _Reference130) содержится более 2 миллионов записей, выполнение такого запроса может занимать от 5 до 15 секунд. Причина кроется в неэффективном использовании индексов СУБД.
Для подчиненных справочников (каким чаще всего и является справочник «Серии номенклатуры», подчиненный «Номенклатуре») платформа 1С строит составные (композитные) индексы. Структура такого индекса выглядит так:
[РазделительОбластейДанных +] Владелец + Код + Ссылка
Поскольку первым (ведущим) полем в индексе идет Владелец (поле _OwnerIDRRef в СУБД), СУБД не может выполнить эффективную операцию поиска по индексу (Index Seek), если в запросе проверяется только Код (поле _Code). Вместо этого СУБД вынуждена выполнять полное сканирование таблицы или индекса (Index Scan / Clustered Index Scan), проверяя каждую из 2 миллионов записей. Это создает колоссальную нагрузку на дисковую подсистему сервера и приводит к зависанию интерфейса у пользователя.
Существует распространенное заблуждение, что для исправления этой проблемы придется переписывать программный код на всех формах конфигурации. На самом деле это не так. Платформа 1С предоставляет элегантный механизм глобального перехвата ввода по строке через модуль менеджера конкретного справочника.
Процедура ОбработкаПолученияДанныхВыбора, расположенная в модуле менеджера проблемного справочника, срабатывает абсолютно на всех формах системы, где выполняется выбор данного объекта. Нам достаточно один раз переопределить стандартную обработку в этом модуле.
Рассмотрим пример оптимизированного кода. Если пользователь вставляет точное значение (например, полный код серии), мы можем заменить ресурсоемкий поиск через оператор LIKE на быстрое точное равенство =:
Процедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка)
СтрокаПоиска = СокрЛП(Параметры.СтрокаПоиска);
Если ПустаяСтрока(СтрокаПоиска) Тогда
Возврат;
КонецЕсли;
// Если длина строки поиска соответствует шаблону полного кода (например, 9 символов)
Если СтрДлина(СтрокаПоиска) >= 9 Тогда
// Отключаем стандартный тяжелый запрос платформы
СтандартнаяОбработка = Ложь;
ДанныеВыбора = Новый СписокЗначений;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 10
| Серии.Ссылка КАК Ссылка,
| Серии.Наименование КАК Представление
|ИЗ
| Справочник.СерииНоменклатуры КАК Серии
|ГДЕ
| Серии.Код = &СтрокаПоиска";
// Обязательно проверяем, передан ли отбор по Владельцу (Номенклатуре)
// Если владелец есть, добавляем его в запрос, чтобы СУБД задействовала составной индекс
Если Параметры.Отбор.Свойство("Владелец") Тогда
Запрос.Текст = СтрЗаменить(Запрос.Текст, "ГДЕ", "ГДЕ Серии.Владелец = &Владелец И");
Запрос.УстановитьПараметр("Владелец", Параметры.Отбор.Владелец);
КонецЕсли;
Запрос.УстановитьПараметр("СтрокаПоиска", СтрокаПоиска);
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
ДанныеВыбора.Добавить(Выборка.Ссылка, Выборка.Представление);
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
С помощью этого несложного алгоритма мы полностью исключаем сканирование таблицы. Поиск по точному соответствию Серии.Код = &СтрокаПоиска (особенно при наличии отбора по владельцу) выполняется СУБД мгновенно — менее чем за 0.01 секунды.
Чтобы СУБД всегда могла использовать составной индекс Владелец + Код, в SQL-запросе обязательно должен присутствовать отбор по владельцу. Для этого необходимо проверить настройки элементов управления на формах документов (например, в табличной части "Товары" при выборе серии).
Выполним следующие шаги в конфигураторе:
Отбор.Владелец и свяжите его с полем Номенклатура текущей строки.Благодаря этой настройке пользователь не сможет выбирать серии, не принадлежащие выбранной номенклатуре, а платформа автоматически добавит условие по полю _OwnerIDRRef в генерируемый SQL-запрос, что позволит СУБД выполнить быстрый Index Seek.
Если бизнес-требования не обязуют искать серии по вхождению в любую часть наименования или кода, обязательно проверьте свойство справочника «Способ поиска при вводе по строке» (вкладка «Поле ввода» в окне редактирования объекта конфигурации):
LIKE '%Значение%'. Наличие знака процента в начале строки поиска полностью исключает использование индексов СУБД.LIKE 'Значение%', что позволит СУБД осуществлять поиск по индексу (при условии, что поиск идет по первому полю индекса или заданы остальные ведущие поля).Для действительно огромных справочников стандартный поиск через SQL-оператор LIKE становится неэффективным. В платформу 1С:Предприятие встроен мощный механизм полнотекстового поиска, специально оптимизированный для быстрого подбора данных.
Для его активации выполните следующие настройки:
При таких настройках платформа при вводе строки будет обращаться не к таблицам базы данных через тяжелые SQL-запросы, а к быстрому полнотекстовому индексу, что сведет время поиска к долям секунды.
Если база данных работает под высокой нагрузкой и кратковременные задержки при поиске все же неизбежны, мы можем защитить интерфейс пользователя от "замерзания".
Для этого в свойствах справочника (на вкладке «Поле ввода») найдите свойство «Режим получения данных выбора» и установите его в значение «Фоновый».
При этом режиме опрос базы данных будет выполняться в фоновом асинхронном задании. Пользователь сможет продолжать перемещать курсор или заполнять другие поля формы, в то время как рядом с полем ввода будет отображаться аккуратный анимированный индикатор поиска. Как только фоновое задание вернет результат, список выбора раскроется автоматически.
Мы подробно разобрали проблему медленного поиска при вводе по строке в больших справочниках 1С и изучили комплекс мер по ее устранению. Для достижения максимальной производительности рекомендуется использовать комбинацию этих методов: настроить связи параметров выбора на формах для задействования индексов СУБД, установить режим поиска «Начало» или подключить полнотекстовый поиск, а при необходимости точечной оптимизации — переопределить процедуру ОбработкаПолученияДанныхВыбора в модуле менеджера справочника.