Как ускорить выполнение запроса по взаиморасчетам и аренде при переходе на 1С:Бухгалтерия 3.0

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

При миграции доработок из старых конфигураций (например, Бухгалтерия предприятия 2.0 на обычных формах) в современные версии на базе БП 3.0 разработчики часто сталкиваются с резким падением производительности запросов. Рассмотрим ситуацию, когда запрос по расчету пеней и задолженности, работавший ранее за секунды, начинает выполняться крайне долго. Проанализируем причины и разберем по шагам методы оптимизации.

Анализ первой причины: Периодичность виртуальных таблиц

Одной из скрытых причин замедления является использование параметра периодичности Запись в виртуальных таблицах остатков и оборотов. Проанализируем фрагмент исходного кода:


РегистрНакопления.АР_ВзаиморасчетыПоАренде.ОстаткиИОбороты(
    &НачалоПериодаНачисленияПени,
    &МоментНачисленияПени,
    Запись,
    ,
    ДоговорКонтрагента = &ДоговорКонтрагента
    И НЕ Депозит
    И НЕ Пени) КАК АР_ВзаиморасчетыПоАрендеОстатки

Выясним, почему это работает медленно. Когда мы указываем периодичность Запись, система 1С:Предприятие игнорирует предварительно рассчитанные таблицы итогов и обращается напрямую к физической таблице движений регистра. В новых версиях платформы и при большом объеме данных это приводит к полному сканированию таблиц БД.

Рекомендация: Если вам не нужны детальные записи до конкретного регистратора в этом месте, замените Запись на Период или Авто. Если же детализация необходима, попробуйте сначала отобрать нужные данные во временную таблицу по индексу (например, только по конкретному договору), а затем уже работать с ними.

Анализ второй причины: Особенности производственного календаря в БП 3.0

В версии 3.0 структура хранения данных календаря изменилась. Теперь используется регистр сведений ДанныеПроизводственногоКалендаря. Рассмотрим типичную ошибку при соединении с этим регистром:


ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеПроизводственногоКалендаря КАК ДанныеПроизводственногоКалендаря
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеПроизводственногоКалендаря КАК ДанныеПроизводственногоКалендаряОграничитель
ПО ДанныеПроизводственногоКалендаря.Дата = Задолженность.СрокОплаты

В 1С:Бухгалтерия 3.0 этот регистр имеет несколько измерений, включая ПроизводственныйКалендарь. Если в вашей базе заведено несколько календарей (например, пятидневка, шестидневка или региональные календари), а в запросе отсутствует фильтр по конкретной ссылке на календарь, происходит «размножение» строк. Система выполняет Cross Join (перекрестное соединение) по всем доступным календарям для каждой даты.

Рекомендация: Всегда добавляйте в условия соединения или в параметры виртуальной таблицы фильтр по конкретному календарю (обычно это основной календарь РФ).

Оптимизация «треугольных соединений» и расчет рабочих дней

Самым «тяжелым» местом в таких запросах обычно является расчет количества дней отсрочки с учетом только рабочих дней. Рассмотрим, как это реализовано в медленном запросе:


ИМЕЮЩИЕ
    СУММА(ВЫБОР
        КОГДА Задолженность.СрокОплаты = ДанныеПроизводственногоКалендаряОграничитель.Дата
            ТОГДА 1
        КОГДА &УчитыватьТолькоРабочиеДниОтсрочки
            ТОГДА ВЫБОР
                КОГДА ДанныеПроизводственногоКалендаря.ВидДня В (&РабочийДень)
                    ТОГДА 1
                ИНАЧЕ 0
            КОНЕЦ
        ИНАЧЕ 1
    КОНЕЦ) = &ДнейОтсрочки + 1

Использование агрегатных функций (СУММА) внутри условия ИМЕЮЩИЕ при соединении таблиц «само на себя» создает колоссальную нагрузку. Это так называемое «треугольное соединение», сложность которого растет в квадратичной прогрессии от количества записей. Если в календаре 8000 записей, СУБД приходится выполнять миллионы операций для сопоставления дат.

Эффективное решение: Метод пронумерованной последовательности

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

  1. Создадим временную таблицу ВтРабочиеДни, отобрав из календаря только рабочие дни за нужный нам период (например, за последние 2-3 года).
  2. Присвоим каждому рабочему дню порядковый номер. Для этого соединим таблицу саму с собой по условию Дата1 >= Дата2 и сгруппируем.
  3. Теперь расчет даты «Дата + 5 рабочих дней» превращается в простое арифметическое действие: Индекс + 5.

Посмотрим на пример реализации такого подхода:


// Шаг 1: Отбираем рабочие дни во временную таблицу
ВЫБРАТЬ
    Календарь.Дата КАК Дата
ПОМЕСТИТЬ ВтРабочиеДни
ИЗ
    РегистрСведений.ДанныеПроизводственногоКалендаря КАК Календарь
ГДЕ
    Календарь.ВидДня В (&СписокРабочихДней)
    И Календарь.Дата МЕЖДУ &ДатаНачала И &ДатаКонца;

// Шаг 2: Индексируем последовательность (присваиваем номер каждому дню)
ВЫБРАТЬ
    Т1.Дата КАК Дата,
    КОЛИЧЕСТВО(Т2.Дата) КАК ПорядковыйНомер
ПОМЕСТИТЬ ВтКалендарьСИндексом
ИЗ
    ВтРабочиеДни КАК Т1
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВтРабочиеДни КАК Т2
    ПО Т1.Дата >= Т2.Дата
СГРУППИРОВАТЬ ПО
    Т1.Дата;
ИНДЕКСИРОВАТЬ ПО
    ПорядковыйНомер,
    Дата;

Теперь в основном запросе мы просто соединяем таблицу задолженности с ВтКалендарьСИндексом по дате, получаем начальный ПорядковыйНомер, прибавляем к нему число дней отсрочки и вторым соединением получаем искомую дату. Этот метод работает в десятки раз быстрее, чем расчет через СУММА(ВЫБОР...).

Дополнительные советы по оптимизации в 3.0

Проанализируем еще несколько важных моментов, которые могут влиять на скорость:

1. Индексация временных таблиц.

Всегда индексируйте временные таблицы по полям, которые участвуют в соединениях (ПО) и условиях (ГДЕ). В нашем случае это ДокументРасчетов, СрокОплаты и ДатаРасчета.

2. Ограничение периода календаря.

В исходном запросе часто забывают ограничить календарь «снизу». Если ваш долг возник в 2023 году, нет смысла тянуть данные календаря с 2001 года. Добавьте условие Дата >= &НачалоПериодаЗадолженности.

3. Влияние RLS (прав доступа).

В 1С:Бухгалтерия 3.0 механизмы разграничения прав доступа на уровне записей (RLS) стали сложнее. Если запрос выполняется под пользователем, платформа добавляет к нему множество дополнительных подзапросов. Для диагностики запустите этот же код под пользователем с полными правами. Если скорость вырастет — проблему нужно искать в настройках профилей групп доступа.

4. Использование временных таблиц вместо вложенных запросов.

Старайтесь избегать конструкций ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ...). Оптимизатор SQL гораздо лучше справляется с плоскими временными таблицами, так как для них статистика распределения данных строится точнее.

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

← На главную