Как ускорить работу модуля «УчетТоваров» в 1С:Бухгалтерии КОРП при расчете себестоимости?

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Бухгалтерский учет
← На главную

При работе с крупными информационными базами «1С:Бухгалтерия КОРП» пользователи и администраторы часто сталкиваются с существенным замедлением операций при закрытии месяца. Одной из наиболее «тяжелых» процедур является корректировка стоимости номенклатуры и расчет себестоимости. Проблема часто кроется в неоптимальных запросах внутри общего модуля УчетТоваров, которые при определенных условиях начинают выполнять полное сканирование таблиц вместо быстрого поиска по индексу.

В этой статье мы подробно разберем, почему стандартные механизмы работы с субконто в виртуальных таблицах могут работать медленно, и как правильно оптимизировать код, чтобы добиться многократного ускорения системы.

Анализ проблемного участка кода

Рассмотрим фрагмент запроса, который обращается к виртуальной таблице ДвиженияССубконто регистра бухгалтерии Хозрасчетный. В типовых решениях часто встречается конструкция, ограничивающая выборку по второму субконто (обычно это «Партии»):


Общиймодуль.УчетТоваров | ИЗ | РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(
| &НачМесяцаРеализации,
| &КонДата,
| Организация = &Организация
| И &УсловиеПоПодразделениюКт
| И СчетКт В (&СчетКтПартионный)
| И НеКорректироватьСтоимостьАвтоматически
| И КоличествоКт < 0
| И ВидСубконтоКт1 = ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Номенклатура)
| И СубконтоКт1 В (&Товары)
| И ВидСубконтоКт2 = ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Партии)
| И ЕСТЬNULL(СубконтоКт2, НЕОПРЕДЕЛЕНО) В (ВЫБРАТЬ ВТ_Партии.Партия ИЗ ВТ_Партии)
| , , ) КАК ХозрасчетныйДвиженияССубконто

Внимательно посмотрим на строку: И ЕСТЬNULL(СубконтоКт2, НЕОПРЕДЕЛЕНО) В (...). Именно здесь скрывается главная причина деградации производительности на больших объемах данных.

Почему ЕСТЬNULL убивает производительность (проблема SARGability)

Проанализируем ситуацию с точки зрения SQL-сервера. Когда мы используем функцию ЕСТЬNULL (в терминах SQL это ISNULL или COALESCE) над колонкой, которая входит в индекс, мы делаем аргумент «не-SARGable» (Searchable Argument). Это означает, что SQL-сервер больше не может использовать Index Seek (быстрый поиск по дереву индекса) для нахождения нужных строк.

Вместо этого сервер вынужден выполнять Index Scan или Table Scan — он берет каждую строку из миллионов записей в таблице, применяет к ней функцию ISNULL, вычисляет результат и только потом сравнивает его со списком из временной таблицы. На базах с миллионами движений такой запрос может выполняться 10–20 минут вместо нескольких секунд.

Особенности хранения субконто в 1С

Выясним причину, по которой разработчики 1С используют такие конструкции. В регистре бухгалтерии Субконто — это составной тип данных. В физических таблицах СУБД значения субконто разнесены по разным колонкам в зависимости от их типа. Когда платформа 1С транслирует обращение к СубконтоКт2, она генерирует сложную конструкцию CASE WHEN....

Если в условии появляется ЕСТЬNULL(СубконтоКт2, НЕОПРЕДЕЛЕНО), платформа пытается обработать ситуацию, когда записи в таблице значений субконто отсутствуют. Однако в контексте виртуальной таблицы ДвиженияССубконто с наложенным фильтром по виду субконто (ВидСубконтоКт2 = ...), значение NULL для самого поля субконто в физической таблице практически исключено, если данные корректны.

Вариант оптимизации №1: Прямое сравнение

Самый простой и эффективный способ ускорить запрос — убрать функцию ЕСТЬNULL. Посмотрим, как изменится условие:


| И ВидСубконтоКт2 = ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Партии)
| И СубконтоКт2 В (ВЫБРАТЬ ВТ_Партии.Партия ИЗ ВТ_Партии)

Важный нюанс: Если вы просто удалите ЕСТЬNULL, необходимо гарантировать, что во временной таблице ВТ_Партии нет значений NULL. В SQL условие Значение В (NULL) всегда возвращает «Ложь», даже если значение само является NULL. Это может привести к потере данных в выборке.

Вариант оптимизации №2: Предварительная очистка данных

Для максимально безопасной и быстрой работы программы проанализируем и подготовим данные во временной таблице ВТ_Партии перед основным запросом. Мы должны исключить из нее пустые значения и значения NULL, чтобы оставить только конкретные ссылки на документы-партии.

Шаги по реализации:

  1. Создадим временную таблицу ВТ_Партии_Очищенная, отобрав только заполненные ссылки.
  2. В основном запросе к ДвиженияССубконто будем использовать эту очищенную таблицу.
  3. Удалим все обертки ЕСТЬNULL вокруг полей субконто.

// Сначала подготавливаем партии
"ВЫБРАТЬ РАЗЛИЧНЫЕ
|   Т.Партия КАК Партия
|ПОМЕСТИТЬ ВТ_Партии_Очищенная
|ИЗ
|   ВТ_Партии КАК Т
|ГДЕ
|   Т.Партия <> ЗНАЧЕНИЕ(Документ.ПоступлениеТоваровУслуг.ПустаяСсылка)
|   И Т.Партия ЕСТЬ НЕ NULL";

// Затем используем в основном запросе
"И СубконтоКт2 В (ВЫБРАТЬ Т.Партия ИЗ ВТ_Партии_Очищенная КАК Т)"

Почему нельзя просто заменить НЕОПРЕДЕЛЕНО на NULL?

Рассмотрим предложение некоторых разработчиков заменить НЕОПРЕДЕЛЕНО на NULL в коде запроса. Это опасный путь. В языке 1С НЕОПРЕДЕЛЕНО — это конкретное значение пустого типа, в то время как NULL в SQL — это отсутствие данных как таковых. Если логика расчета предполагает поиск движений, где партия не указана (пустое значение), то замена на NULL в условии В (...) приведет к тому, что эти строки никогда не попадут в результат. Это вызовет ошибки в расчете остатков и себестоимости, которые будет крайне сложно диагностировать позже.

Итоги и рекомендации

Подведем итог нашему исследованию способов ускорения «Бухгалтерии КОРП»:

Соблюдение этих правил позволит вашей конфигурации работать максимально производительно даже при значительном росте объема учетных данных.

← На главную