Какие данные возвращает запрос по начислениям отпуска и почему его реализация считается антипаттерном

Программист 1С v8.3 (Обычные формы) 1С:Зарплата и Управление Персоналом Управленческий учет IT и автоматизация бизнеса
← На главную

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

Что именно возвращает данный запрос?

Проанализируем структуру выборки. Запрос обращается к двум источникам данных: виртуальной таблице среза последних фамилий сотрудников и табличной части документа начисления отпуска. В результате выполнения мы получим список физических лиц (Фамилия, Имя, Отчество) и соответствующие им суммы (поле Результат), которые были зафиксированы в документах НачислениеОтпускаРаботникамОрганизаций за определенный период.

Основные фильтры, наложенные на результат:

  1. Месяц регистрации документа должен быть больше или равен параметру &Дата1.
  2. Документ должен находиться в статусе проведения (параметр &Проведен).
  3. Выборка ограничена конкретной организацией и физическим лицом, при этом реализована логика «если параметр не заполнен, выбираем всех».

Проблема 1: Обращение к документам вместо регистров

Разберем методологическую ошибку. В системе 1С:Предприятие документы — это инструменты регистрации намерений или фактов хозяйственной деятельности. Однако сами данные для отчетности должны извлекаться из регистров (накопления или расчета).

Выясним причину, почему обращение к табличной части Начисления документа напрямую — это плохо:

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

Проблема 2: Разыменование полей через точку (Dot Counting)

Проанализируем секцию ГДЕ. Мы видим конструкции типа НачислениеОтпуска...Начисления.Ссылка.Организация. В языке запросов 1С обращение через точку от ссылочного поля к реквизиту объекта приводит к неявному использованию соединения ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN) на уровне SQL-запроса.

Когда таких обращений много, СУБД генерирует тяжелый план запроса с множеством лишних соединений. Рассмотрим, как это выглядит для сервера:


// Это кажется одной строкой в 1С
ГДЕ ТабличнаяЧасть.Ссылка.Организация = &Организация

// Превращается в SQL примерно в такое:
LEFT JOIN Документ_НачислениеОтпуска Т2 ON Т1.Ссылка = Т2.ID
WHERE Т2.Организация = @P1

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

Проблема 3: Некорректное использование «Среза последних»

Посмотрим на обращение к РегистрСведений.ФИОФизЛиц.СрезПоследних. В запросе не указан параметр Период. Это означает, что система получит фамилии сотрудников, актуальные на текущий момент времени (момент запуска запроса).

Представим ситуацию: вы формируете отчет за 2022 год. Сотрудница Иванова в 2023 году вышла замуж и стала Петровой. Из-за отсутствия привязки среза к дате документа, в отчете за 2022 год она отобразится как Петрова. Это искажает историческую достоверность данных. Срез последних всегда должен браться либо на дату документа, либо на конец периода формирования отчета.

Проблема 4: Тяжелые подзапросы в условиях фильтрации

Разберем конструкцию, которая используется для обработки пустых параметров:


И НачислениеОтпуска...Ссылка.Организация В
(ВЫБРАТЬ ВЫБОР КОГДА &Организация = ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка)
 ТОГДА Организации.Ссылка ИНАЧЕ &Организация КОНЕЦ
 ИЗ Справочник.Организации КАК Организации)

Такой подход заставляет СУБД выполнять полный скан справочника организаций или физических лиц при каждом выполнении запроса, если параметр пуст. Для справочника ФизическиеЛица, в котором могут быть десятки тысяч записей, это критично. Более того, существует ограничение SQL-сервера на количество элементов в операторе IN (обычно около 1000). Если у вас 2000 сотрудников, этот запрос может просто завершиться с ошибкой.

Как оптимизировать: лучше использовать динамическое формирование текста запроса в коде 1С или простое условие:


ГДЕ (&Организация = ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка) ИЛИ ПолеОрганизация = &Организация)

Проблема 5: Дублирование строк при соединении

В запросе используется ВНУТРЕННЕЕ СОЕДИНЕНИЕ по полю ФизЛицо. Если в одном документе «Начисление отпуска» сотрудник фигурирует в нескольких строках табличной части (например, отпуск разбит на основной и дополнительный или по разным периодам), то каждая строка начисления соединится с данными из регистра сведений. В итоге мы получим несколько строк по одному человеку. Если целью было получение общей суммы по документу, результат будет некорректным без использования группировки СГРУППИРОВАТЬ ПО.

Рекомендуемая стратегия исправления

Чтобы превратить этот код в качественный продукт, нам следует придерживаться следующего алгоритма:

  1. Использовать временные таблицы. Сначала выберем список нужных сотрудников и документов в МенеджерВременныхТаблиц.
  2. Работать с регистрами. Заменим обращение к Документ...Начисления на виртуальную таблицу РегистрРасчета.Начисления.ФактическийПериодДействия.
  3. Передать параметры в ВТ. Дату среза последних и период регистрации начислений нужно передавать непосредственно в параметры виртуальных таблиц, а не фильтровать через ГДЕ.
  4. Оптимизировать фильтры. Отказаться от конструкции ВЫБОР внутри В (ВЫБРАТЬ...) в пользу логического ИЛИ в условии.

Соблюдение этих правил обеспечит стабильную работу системы даже при значительном росте объема данных в базе 1С:Зарплата и Управление Персоналом.

← На главную