При доработке типового поиска в конфигурации 1С:Управление торговлей 10.3 разработчики часто сталкиваются с существенным падением производительности. Попытка организовать поиск по нескольким словам наименования, артикулам, брендам и дополнительной таблице кроссов нередко приводит к тому, что запрос выполняется по 15–20 секунд. Разберем причины такого поведения платформы и СУБД, а также пошагово реализуем эффективные варианты решения проблемы.
Рассмотрим структуру исходного запроса, вызывающего длительные задержки. В нем выполняется левое соединение справочника кроссов со справочником Номенклатура с фильтрацией по условию ПОДОБНО и точному совпадению через ОБЪЕДИНИТЬ ВСЕ:
ВЫБРАТЬ РАЗЛИЧНЫЕ
СправочникНоменклатура.Ссылка КАК Номенклатура,
СправочникНоменклатура.Артикул,
СправочникНоменклатура.Родитель,
СправочникНоменклатура.Код
ИЗ
Справочник.СайтКроссыТоваров КАК СайтКроссыТоваров
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК СправочникНоменклатура
ПО СайтКроссыТоваров.Артикул = СправочникНоменклатура.ПолеПоиска
И СайтКроссыТоваров.Бренд = СправочникНоменклатура.Бренд
ГДЕ
СайтКроссыТоваров.КроссПоисковыйАртикул ПОДОБНО &Представление
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
НоменклатураСправочник.Ссылка,
НоменклатураСправочник.Артикул,
НоменклатураСправочник.Родитель,
НоменклатураСправочник.Код
ИЗ
Справочник.СайтКроссыТоваров КАК СайтКроссыТоваров
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК НоменклатураСправочник
ПО СайтКроссыТоваров.Артикул = НоменклатураСправочник.ПолеПоиска
И СайтКроссыТоваров.Бренд = НоменклатураСправочник.Бренд
ГДЕ
СайтКроссыТоваров.КроссПоисковыйАртикул = &Крос
Выделим ключевые узкие места этого решения:
&Представление начинается с подстановочного знака %, реляционная СУБД принципиально не может использовать индекс B-Tree по реквизиту КроссПоисковыйАртикул. Это приводит к полному сканированию всей таблицы (Table Scan).ПОДОБНО "%значение%". Выполнять повторное чтение таблицы через ОБЪЕДИНИТЬ ВСЕ по условию точного равенства избыточно.Артикул и Бренд) выполняется медленно, особенно при отсутствии составного индекса.Первый шаг оптимизации заключается в том, чтобы сначала ограничить набор данных из таблицы кроссов, поместить отобранные пары полей во временную таблицу, проиндексировать их и только затем соединять со справочником Номенклатура.
Перепишем запрос следующим образом:
ВЫБРАТЬ
СайтКроссыТоваров.Бренд КАК Бренд,
СайтКроссыТоваров.Артикул КАК Артикул
ПОМЕСТИТЬ втСайтКроссыТоваров
ИЗ
Справочник.СайтКроссыТоваров КАК СайтКроссыТоваров
ГДЕ
СайтКроссыТоваров.КроссПоисковыйАртикул ПОДОБНО &Представление
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СайтКроссыТоваров.Бренд,
СайтКроссыТоваров.Артикул
ИЗ
Справочник.СайтКроссыТоваров КАК СайтКроссыТоваров
ГДЕ
СайтКроссыТоваров.КроссПоисковыйАртикул = &Крос
ИНДЕКСИРОВАТЬ ПО
Бренд,
Артикул
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
СправочникНоменклатура.Ссылка КАК Ссылка,
СправочникНоменклатура.Артикул КАК Артикул,
СправочникНоменклатура.Родитель КАК Родитель,
СправочникНоменклатура.Код КАК Код
ИЗ
втСайтКроссыТоваров КАК втСайтКроссыТоваров
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК СправочникНоменклатура
ПО втСайтКроссыТоваров.Артикул = СправочникНоменклатура.ПолеПоиска
И втСайтКроссыТоваров.Бренд = СправочникНоменклатура.Бренд
Обратим внимание на важные правила построения таких запросов:
ЛЕВОЕ СОЕДИНЕНИЕ.Бренд является ссылочным типом, а Артикул — строкой, в секции индексации первым указываем ссылочное поле (Бренд, Артикул). Сравнение ссылок и чисел в индексах СУБД выполняется быстрее, чем строковых данных.ГДЕ Поле = &Парам ИЛИ Поле ПОДОБНО &Парам2 приводит к невозможности применения индексов в большинстве СУБД. Конструкция с ОБЪЕДИНИТЬ ВСЕ работает быстрее и предсказуемее.Даже с временными таблицами поиск по подстроке ПОДОБНО "%123%" заставляет сервер сканировать всю таблицу кроссов. Для достижения мгновенного отклика (доли секунды) применим архитектурную оптимизацию:
ОчищенныйАртикул) и установим ему свойство Индексировать.ПередЗаписью программно очищаем строку: удаляем пробелы, дефисы, точки, слэши и переводим символы в верхний регистр. При поиске введенную пользователем строку обрабатываем точно так же.ПОДОБНО &ОчищенныйАртикул + "%". В этом случае СУБД способна использовать индекс (Index Seek), так как начало строки строго фиксировано.Использование справочника для хранения кросс-кодов создает избыточную нагрузку на дисковую подсистему: справочник хранит ссылки, код, наименование, системные реквизиты и версии данных. Для автокроссов оптимально использовать непериодический независимый регистр сведений со следующей структурой измерений:
КроссАртикулОчищенный (Строка, индексировать);Бренд (СправочникСсылка.Бренды или Строка);Номенклатура (СправочникСсылка.Номенклатура).В регистрах сведений платформа автоматически формирует кластерный индекс по измерениям в порядке их следования. Поместив поисковый артикул на первое место в списке измерений, мы получаем максимально возможную скорость выборки без необходимости создания громоздких временных таблиц.
Когда требуется искать номенклатуру по произвольной комбинации слов наименования (например, «болт амор подвес Камаз»), использование множественных условий ПОДОБНО в цикле или запросе перегружает сервер. Для таких задач предназначен встроенный механизм полнотекстового поиска 1С:
СписокНайдено = ПолнотекстовыйПоиск.СоздатьСписок("болт* И амор* И подвес* И Камаз*");
СписокНайдено.ОбластьПоиска.Добавить(Метаданные.Справочники.Номенклатура);
СписокНайдено.ПерваяЧасть();
МассивСсылок = Новый Массив;
Для Каждого Элемент Из СписокНайдено Цикл
МассивСсылок.Добавить(Элемент.Значение);
КонецЦикла;
Механизм полнотекстового поиска использует инвертированный индекс и специализированные словари морфологии, выдавая результат за миллисекунды независимо от объема каталога товаров. При его использовании необходимо настроить регулярное фоновое задание по обновлению индекса методом ПолнотекстовыйПоиск.ОбновитьИндекс().