При работе с крупными информационными базами «1С:Бухгалтерия КОРП» пользователи и администраторы часто сталкиваются с существенным замедлением операций при закрытии месяца. Одной из наиболее «тяжелых» процедур является корректировка стоимости номенклатуры и расчет себестоимости. Проблема часто кроется в неоптимальных запросах внутри общего модуля УчетТоваров, которые при определенных условиях начинают выполнять полное сканирование таблиц вместо быстрого поиска по индексу.
В этой статье мы подробно разберем, почему стандартные механизмы работы с субконто в виртуальных таблицах могут работать медленно, и как правильно оптимизировать код, чтобы добиться многократного ускорения системы.
Рассмотрим фрагмент запроса, который обращается к виртуальной таблице ДвиженияССубконто регистра бухгалтерии Хозрасчетный. В типовых решениях часто встречается конструкция, ограничивающая выборку по второму субконто (обычно это «Партии»):
Общиймодуль.УчетТоваров | ИЗ | РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(
| &НачМесяцаРеализации,
| &КонДата,
| Организация = &Организация
| И &УсловиеПоПодразделениюКт
| И СчетКт В (&СчетКтПартионный)
| И НеКорректироватьСтоимостьАвтоматически
| И КоличествоКт < 0
| И ВидСубконтоКт1 = ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Номенклатура)
| И СубконтоКт1 В (&Товары)
| И ВидСубконтоКт2 = ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Партии)
| И ЕСТЬNULL(СубконтоКт2, НЕОПРЕДЕЛЕНО) В (ВЫБРАТЬ ВТ_Партии.Партия ИЗ ВТ_Партии)
| , , ) КАК ХозрасчетныйДвиженияССубконто
Внимательно посмотрим на строку: И ЕСТЬNULL(СубконтоКт2, НЕОПРЕДЕЛЕНО) В (...). Именно здесь скрывается главная причина деградации производительности на больших объемах данных.
Проанализируем ситуацию с точки зрения SQL-сервера. Когда мы используем функцию ЕСТЬNULL (в терминах SQL это ISNULL или COALESCE) над колонкой, которая входит в индекс, мы делаем аргумент «не-SARGable» (Searchable Argument). Это означает, что SQL-сервер больше не может использовать Index Seek (быстрый поиск по дереву индекса) для нахождения нужных строк.
Вместо этого сервер вынужден выполнять Index Scan или Table Scan — он берет каждую строку из миллионов записей в таблице, применяет к ней функцию ISNULL, вычисляет результат и только потом сравнивает его со списком из временной таблицы. На базах с миллионами движений такой запрос может выполняться 10–20 минут вместо нескольких секунд.
Выясним причину, по которой разработчики 1С используют такие конструкции. В регистре бухгалтерии Субконто — это составной тип данных. В физических таблицах СУБД значения субконто разнесены по разным колонкам в зависимости от их типа. Когда платформа 1С транслирует обращение к СубконтоКт2, она генерирует сложную конструкцию CASE WHEN....
Если в условии появляется ЕСТЬNULL(СубконтоКт2, НЕОПРЕДЕЛЕНО), платформа пытается обработать ситуацию, когда записи в таблице значений субконто отсутствуют. Однако в контексте виртуальной таблицы ДвиженияССубконто с наложенным фильтром по виду субконто (ВидСубконтоКт2 = ...), значение NULL для самого поля субконто в физической таблице практически исключено, если данные корректны.
Самый простой и эффективный способ ускорить запрос — убрать функцию ЕСТЬNULL. Посмотрим, как изменится условие:
| И ВидСубконтоКт2 = ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Партии)
| И СубконтоКт2 В (ВЫБРАТЬ ВТ_Партии.Партия ИЗ ВТ_Партии)
Важный нюанс: Если вы просто удалите ЕСТЬNULL, необходимо гарантировать, что во временной таблице ВТ_Партии нет значений NULL. В SQL условие Значение В (NULL) всегда возвращает «Ложь», даже если значение само является NULL. Это может привести к потере данных в выборке.
Для максимально безопасной и быстрой работы программы проанализируем и подготовим данные во временной таблице ВТ_Партии перед основным запросом. Мы должны исключить из нее пустые значения и значения NULL, чтобы оставить только конкретные ссылки на документы-партии.
Шаги по реализации:
ВТ_Партии_Очищенная, отобрав только заполненные ссылки.ДвиженияССубконто будем использовать эту очищенную таблицу.ЕСТЬNULL вокруг полей субконто.
// Сначала подготавливаем партии
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Т.Партия КАК Партия
|ПОМЕСТИТЬ ВТ_Партии_Очищенная
|ИЗ
| ВТ_Партии КАК Т
|ГДЕ
| Т.Партия <> ЗНАЧЕНИЕ(Документ.ПоступлениеТоваровУслуг.ПустаяСсылка)
| И Т.Партия ЕСТЬ НЕ NULL";
// Затем используем в основном запросе
"И СубконтоКт2 В (ВЫБРАТЬ Т.Партия ИЗ ВТ_Партии_Очищенная КАК Т)"
Рассмотрим предложение некоторых разработчиков заменить НЕОПРЕДЕЛЕНО на NULL в коде запроса. Это опасный путь. В языке 1С НЕОПРЕДЕЛЕНО — это конкретное значение пустого типа, в то время как NULL в SQL — это отсутствие данных как таковых. Если логика расчета предполагает поиск движений, где партия не указана (пустое значение), то замена на NULL в условии В (...) приведет к тому, что эти строки никогда не попадут в результат. Это вызовет ошибки в расчете остатков и себестоимости, которые будет крайне сложно диагностировать позже.
Подведем итог нашему исследованию способов ускорения «Бухгалтерии КОРП»:
ЕСТЬNULL, ПОДСТРОКА, ГОД) превращает быстрый поиск по индексу в медленное сканирование всей таблицы.NULL и лишних пустых ссылок.ГДЕ или в параметрах виртуальных таблиц.Соблюдение этих правил позволит вашей конфигурации работать максимально производительно даже при значительном росте объема учетных данных.