Как оптимизировать запрос по физическим лицам и контактной информации в 1С:ЗУП 2.5?

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

В конфигурации 1С:Зарплата и Управление Персоналом 2.5 (ЗУП 2.5) отчеты по персональным данным часто становятся «узким местом» производительности. Когда необходимо собрать воедино данные справочника ФизическиеЛица, паспортные данные из регистров сведений и контактную информацию, запрос может выполняться недопустимо долго. Рассмотрим причины низкой скорости и разберем по шагам, как превратить тяжеловесный запрос в эффективный инструмент.

Проблема 1: Избыточность выборки данных

Проанализируем первую часть исходного запроса. Зачастую разработчики выбирают всех физических лиц из справочника, включая тех, кто давно уволен или вообще никогда не принимался на работу. Если в базе десятки тысяч записей, это создает колоссальную нагрузку. Первое правило оптимизации — максимально сузить выборку еще на этапе формирования первой временной таблицы.

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

Проблема 2: Использование временных таблиц без индексации

В исходном коде создается временная таблица ВТ_ОбщееФизЛица. Однако при последующих соединениях система вынуждена каждый раз полностью сканировать эту таблицу (Table Scan), так как в ней отсутствуют индексы. Выясним, как это исправить.

Для ускорения работы левых соединений (LEFT JOIN) необходимо индексировать поля связи. Разберем на примере:


ВЫБРАТЬ
    ФизическиеЛица.Ссылка КАК ФизЛицо,
    ФизическиеЛица.ДатаРождения,
    ФизическиеЛица.ИНН
ПОМЕСТИТЬ ВТ_ОбщееФизЛица
ИЗ
    Справочник.ФизическиеЛица КАК ФизическиеЛица
ГДЕ
    ФизическиеЛица.ПометкаУдаления = ЛОЖЬ
    И ФизическиеЛица.ЭтоГруппа = ЛОЖЬ
;
ИНДЕКСИРОВАТЬ ПО
    ФизЛицо
;

Добавление инструкции ИНДЕКСИРОВАТЬ ПО позволит СУБД мгновенно находить нужные строки при соединении с другими таблицами в последующих пакетах.

Проблема 3: Неоптимальное получение контактной информации

Проанализируем ситуацию с контактной информацией (КИ). В исходном запросе используется ОБЪЕДИНИТЬ ВСЕ и тяжелая агрегатная функция МАКСИМУМ с использованием ПОДСТРОКА. Это одна из самых ресурсоемких операций. Регистр сведений КонтактнаяИнформация в ЗУП 2.5 имеет специфическую структуру, и соединение с ним «в лоб» через объединения заставляет систему выполнять несколько проходов по одной и той же таблице.

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


ВЫБРАТЬ
    ВТ.ФизЛицо,
    КИ_Адрес.Представление КАК АдресПроживания,
    КИ_Телефон.Представление КАК ТелефонМобильный
ИЗ
    ВТ_ОбщееФизЛица КАК ВТ
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК КИ_Адрес
        ПО ВТ.ФизЛицо = КИ_Адрес.Объект
        И КИ_Адрес.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Адрес)
        И КИ_Адрес.Вид = ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.ФактАдресФизЛица)
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК КИ_Телефон
        ПО ВТ.ФизЛицо = КИ_Телефон.Объект
        И КИ_Телефон.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Телефон)
        И КИ_Телефон.Вид = ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.ТелефонФизЛица)

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

Проблема 4: Декартово произведение (Cross Join)

В последнем пакете исходного запроса была допущена критическая ошибка: таблицы перечислены через запятую без условий связи (ПО ...). В терминах SQL это называется Cross Join. Если в первой таблице 100 записей, а во второй 100, результат будет содержать 10 000 строк. На реальных базах это приводит к зависанию системы и переполнению памяти.

Рассмотрим правильный подход к сборке финальной таблицы. Все данные должны быть строго связаны по полю ФизЛицо. При этом важно использовать ЛЕВОЕ СОЕДИНЕНИЕ, чтобы не потерять людей, у которых, например, не заполнен телефон или паспортные данные.

Итоговый оптимизированный алгоритм

Разберем по шагам, как должен выглядеть качественный запрос для ЗУП 2.5:

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

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

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

← На главную