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