Часто в процессе эксплуатации 1С:Розница (а также УТ) администраторы и программисты сталкиваются с ситуацией, когда поиск товара по штрихкоду происходит мгновенно для одних позиций и занимает десятки секунд для других. При этом в базе данных записи выглядят абсолютно идентично. В ходе анализа данной проблемы мы выяснили, что причина кроется в неоптимальной структуре запроса, который выполняет поиск в РегистрСведений.СоответствиеНоменклатурыЕГАИС.
Проблема заключается в формировании промежуточных выборок СУБД. В типовом коде запрос зачастую пытается объединить одну и ту же таблицу с данными регистра несколько раз, используя сложные конструкции ВЫБОР КОГДА прямо внутри соединений ЛЕВОЕ СОЕДИНЕНИЕ. Когда СУБД обрабатывает такой запрос, она может пытаться создать декартово произведение (Cartesian Product), перемножая тысячи строк, что приводит к экспоненциальному росту нагрузки на сервер и длительному времени выполнения Запрос.Выполнить().Выгрузить().
Чтобы исключить «перемножение» строк, необходимо отказаться от попытки объединить все данные в один «тяжелый» запрос. Вместо этого мы разделим процесс получения данных на несколько этапов с использованием временных таблиц. Это позволит оптимизатору СУБД работать с четко определенными, небольшими промежуточными выборками.
Разберем по шагам алгоритм оптимизации:
серии и соотв.Посмотрим, как выглядит переработанный код запроса, который позволяет избежать декартова произведения:
ВЫБРАТЬ
ТаблицаНоменклатуры.Номенклатура КАК Номенклатура,
ТаблицаНоменклатуры.Характеристика КАК Характеристика,
ТаблицаНоменклатуры.Серия КАК Серия
ПОМЕСТИТЬ ТаблицаНоменклатуры
ИЗ
&ТаблицаНоменклатуры КАК ТаблицаНоменклатуры
ИНДЕКСИРОВАТЬ ПО
Номенклатура, Характеристика, Серия
;
ВЫБРАТЬ РАЗЛИЧНЫЕ
Т.Номенклатура КАК Номенклатура,
Т.Характеристика КАК Характеристика,
Т.Серия КАК Серия,
СоответствиеСерии.АлкогольнаяПродукция КАК АлкогольнаяПродукция
ПОМЕСТИТЬ серии
ИЗ
ТаблицаНоменклатуры КАК Т
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СоответствиеНоменклатурыЕГАИС КАК СоответствиеСерии
ПО (СоответствиеСерии.Номенклатура = Т.Номенклатура)
И (СоответствиеСерии.Характеристика = Т.Характеристика)
И (СоответствиеСерии.Серия = Т.Серия)
;
ВЫБРАТЬ РАЗЛИЧНЫЕ
Т.Номенклатура КАК Номенклатура,
Т.Характеристика КАК Характеристика,
Т.Серия КАК Серия,
СоответствиеНоменклатура.АлкогольнаяПродукция КАК АлкогольнаяПродукция
ПОМЕСТИТЬ соотв
ИЗ
ТаблицаНоменклатуры КАК Т
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СоответствиеНоменклатурыЕГАИС КАК СоответствиеНоменклатура
ПО (СоответствиеНоменклатура.Номенклатура = Т.Номенклатура)
И (СоответствиеНоменклатура.Характеристика = Т.Характеристика)
И (СоответствиеНоменклатура.Серия В (&ПустыеЗначенияСерий))
;
ВЫБРАТЬ РАЗЛИЧНЫЕ
Т.Номенклатура КАК Номенклатура,
Т.Характеристика КАК Характеристика,
Т.Серия КАК Серия,
ВЫБОР
КОГДА серии.АлкогольнаяПродукция ЕСТЬ NULL
И соотв.АлкогольнаяПродукция ЕСТЬ NULL
ТОГДА ЗНАЧЕНИЕ(Справочник.КлассификаторАлкогольнойПродукцииЕГАИС.ПустаяСсылка)
КОГДА НЕ серии.АлкогольнаяПродукция ЕСТЬ NULL
ТОГДА серии.АлкогольнаяПродукция
ИНАЧЕ соотв.АлкогольнаяПродукция
КОНЕЦ КАК АлкогольнаяПродукция
ИЗ
ТаблицаНоменклатуры КАК Т
ЛЕВОЕ СОЕДИНЕНИЕ серии КАК серии
ПО (серии.Номенклатура = Т.Номенклатура)
И (серии.Характеристика = Т.Характеристика)
И (серии.Серия = Т.Серия)
ЛЕВОЕ СОЕДИНЕНИЕ соотв КАК соотв
ПО (соотв.Номенклатура = Т.Номенклатура)
И (соотв.Характеристика = Т.Характеристика)
И (соотв.Серия В (&ПустыеЗначенияСерий))
Во-первых, мы значительно уменьшаем размерность данных на промежуточных этапах. В первом подзапросе мы получаем 1500 строк, во втором также 1500, но за счет того, что мы выносим их в отдельные временные таблицы, мы предотвращаем перемножение этих наборов данных в 2.5 миллиона строк внутри СУБД.
Во-вторых, использование ВЫБОР КОГДА перенесено в финальный этап, где количество записей уже сокращено до минимума (в нашем примере до 3 строк). Оптимизатору гораздо проще вычислить итоговые значения, когда объем данных для обработки минимален.
В-третьих, мы рекомендуем проверять актуальность статистики на сервере SQL. Если проблема периодически возникает для разных штрихкодов, это часто указывает на то, что план выполнения запроса устарел из-за изменений в данных регистра. Выполнение Update Statistics для таблиц регистра сведений может существенно помочь в подобных ситуациях.
Если вы работаете в конфигурации с множеством узлов РИБ, старайтесь вносить изменения через Расширения конфигурации. Это позволит безопасно внедрить оптимизацию, не затрагивая основной код типовой конфигурации и упрощая дальнейшее обновление системы.