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