Проблема производительности запросов — одна из самых актуальных задач для разработчика 1С. Часто мы сталкиваемся с тем, что отчеты или обработки, которые быстро работали на этапе разработки, начинают "тормозить" на реальных данных у заказчика. В данной статье мы подробно разберем методы оптимизации, основываясь на практическом опыте решения проблем с медленными выборками.
Одной из главных причин низкой производительности являются вложенные запросы, особенно те, которые участвуют в соединениях (ЛЕВОЕ СОЕДИНЕНИЕ или ВНУТРЕННЕЕ СОЕДИНЕНИЕ). Когда СУБД встречает вложенный запрос в условии соединения, она зачастую не может эффективно использовать индексы, что приводит к полному сканированию таблиц.
Рассмотрим, как можно улучшить ситуацию. Вместо того чтобы писать вложенный запрос непосредственно в секции соединений, мы рекомендуем использовать временные таблицы. Проанализируем пример кода, который часто вызывает проблемы:
// Плохой пример: вложенный запрос в соединении
ВЫБРАТЬ
Продажи.Номенклатура,
ВложенныйЗапрос.Остаток
ИЗ
РегистрНакопления.Продажи КАК Продажи
ЛЕВОЕ СОЕДИНЕНИЕ (
ВЫБРАТЬ
Остатки.Номенклатура,
Остатки.КоличествоОстаток КАК Остаток
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
) КАК ВложенныйЗапрос
ПО Продажи.Номенклатура = ВложенныйЗапрос.Номенклатура
Выясним причину, почему это плохо: СУБД вынуждена сначала выполнить вложенный запрос, а затем соединить его результат с основной таблицей без возможности использовать индекс по Номенклатура во временном наборе данных. Чтобы исправить это, разберем по шагам правильный подход с использованием объекта МенеджерВременныхТаблиц.
Для оптимизации мы должны сначала выбрать данные во временную таблицу и обязательно проиндексировать поля, по которым будет происходить соединение. Это позволяет СУБД использовать эффективные алгоритмы поиска (например, Index Seek вместо Scan).
Посмотрим на пример правильной реализации:
// Правильный пример с использованием временной таблицы
ВЫБРАТЬ
Остатки.Номенклатура КАК Номенклатура,
Остатки.КоличествоОстаток КАК Остаток
ПОМЕСТИТЬ ВТ_Остатки
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
;
////////////////////////////////////////////////////////////////////////////////
ИНДЕКСИРОВАТЬ ПО
Номенклатура
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Продажи.Номенклатура,
ВТ_Остатки.Остаток
ИЗ
РегистрНакопления.Продажи КАК Продажи
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Остатки КАК ВТ_Остатки
ПО Продажи.Номенклатура = ВТ_Остатки.Номенклатура
Обратите внимание на ключевое слово ИНДЕКСИРОВАТЬ ПО. В 1С 8.3 при создании временной таблицы в одном пакете запроса мы можем сразу указать поля для индексации. Это критически важно для больших объемов данных.
Проанализируем работу с виртуальными таблицами, такими как Остатки, Обороты или СрезПоследних. Распространенной ошибкой является наложение условий на эти таблицы через секцию ГДЕ основного запроса вместо использования параметров самой виртуальной таблицы.
Рассмотрим подробнее: когда вы используете ГДЕ, 1С сначала получает все данные из виртуальной таблицы, и только потом фильтрует их. Если же условие передано в параметры виртуальной таблицы, фильтрация происходит на уровне формирования выборки внутри СУБД, что значительно быстрее.
Пример оптимизации параметров виртуальной таблицы:
// Оптимально: условие в параметрах
ВЫБРАТЬ
Остатки.КоличествоОстаток
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Номенклатура = &ВыбраннаяНоменклатура) КАК Остатки
В данном случае система обратится только к нужным записям регистра, используя индекс по измерению Номенклатура.
Еще один важный аспект — обращение к реквизитам через точку от ссылочного поля (например, Продажи.Номенклатура.Артикул). Проанализируем ситуацию: каждое такое обращение в запросе порождает неявное ЛЕВОЕ СОЕДИНЕНИЕ с соответствующей таблицей справочника. Если таких обращений много, структура результирующего SQL-запроса становится крайне громоздкой.
Рекомендация: если вам нужно получить несколько реквизитов одного справочника, лучше один раз явно соединиться с этой таблицей в запросе. Это сделает код прозрачнее и позволит оптимизатору СУБД лучше построить план выполнения.
ГДЕ.НАЧАЛОПЕРИОДА от поля таблицы), так как это отключает использование индекса.ГДЕ Номенклатура В (ВЫБРАТЬ...). Заменяйте её на ВНУТРЕННЕЕ СОЕДИНЕНИЕ с временной таблицей.Выясним, когда временные таблицы могут навредить. Если данных совсем мало (десятки строк), создание временной таблицы может занять больше времени, чем прямой запрос. Однако в реальных бизнес-задачах количество данных почти всегда оправдывает использование ВТ.
Подводя итог, мы проанализировали основные приемы ускорения работы с данными. Применение временных таблиц, правильная индексация и грамотная работа с параметрами виртуальных таблиц позволяют сократить время выполнения запросов в десятки и сотни раз, обеспечивая комфортную работу пользователей в системе 1С.