Зачем в ЗУП 3.1 используется странный запрос при установке параметра сеанса АльтернативныйПодборСпискаСотрудников?

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

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

Анализируем исходный код запроса

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


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

На первый взгляд, этот запрос всегда должен возвращать единицу и выполняться успешно. Однако ключевым моментом здесь является блок Попытка...Исключение. Смысл этого кода не в получении данных, а в проверке самой возможности выполнения такой синтаксической конструкции на конкретном сервере СУБД.

Понятие Feature Detection в разработке на 1С

Проанализируем ситуацию: платформа 1С является кроссплатформенной и работает с различными СУБД (MS SQL Server, PostgreSQL, Oracle, IBM DB2). Каждая из этих систем имеет свои особенности реализации стандарта SQL. Метод, представленный в коде, называется feature detection (определение возможностей). Вместо того чтобы проверять версию СУБД или её название, система просто пробует выполнить «проблемный» запрос. Если он падает с ошибкой — значит, данная СУБД не поддерживает такую логику, и нужно использовать обходной путь.

Проблема коррелированных подзапросов в PostgreSQL

Выясним причину, по которой этот код вообще появился. Основная цель данной проверки — выявить ограничения некоторых версий СУБД PostgreSQL. Проблема заключается в использовании конструкции ВЫБРАТЬ ПЕРВЫЕ 1 (аналог LIMIT 1) совместно с УПОРЯДОЧИТЬ ПО (ORDER BY) внутри коррелированного подзапроса.

Коррелированный подзапрос — это подзапрос, который обращается к полям внешней таблицы (в нашем примере это условие ГДЕ ТестируемаяТаблицаОтбор.Номер = ТестируемаяТаблица.Номер). Некоторые сборки PostgreSQL некорректно обрабатывают такие конструкции, если в них присутствует сортировка, или выдают крайне неоптимальный план выполнения, что может привести к критической ошибке или зависанию рабочего процесса.

Разберем по шагам: как это работает в ЗУП

Давайте посмотрим, как результат этой проверки влияет на дальнейшую работу программы. В ЗУП 3.1 параметр сеанса АльтернативныйПодборСпискаСотрудников используется при построении динамических списков сотрудников и в механизмах RLS (ограничение доступа на уровне записей).

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

Рассмотрим разницу на примере логики запроса. Допустим, нам нужно найти последнее подразделение сотрудника. Основной вариант будет выглядеть примерно так:


ГДЕ Подразделение В (ВЫБРАТЬ ПЕРВЫЕ 1 Т.Подразделение ИЗ Таблица КАК Т ГДЕ Т.Сотрудник = ОсновнаяТаблица.Сотрудник УПОРЯДОЧИТЬ ПО Т.Период УБЫВ)

А альтернативный вариант, который гарантированно сработает на любой СУБД, заменит это на:


ГДЕ Подразделение В (ВЫБРАТЬ МАКСИМУМ(Т.Подразделение) ИЗ Таблица КАК Т ГДЕ Т.Сотрудник = ОсновнаяТаблица.Сотрудник)

Важный нюанс: использование МАКСИМУМ не всегда идентично ПЕРВЫЕ 1 с сортировкой по дате, поэтому разработчики 1С применяют этот метод только тогда, когда это допустимо с точки зрения бизнес-логики, или когда другого способа избежать ошибки СУБД просто нет.

Почему это критично для производительности?

Проанализируем ситуацию с точки зрения системного администратора. Если ваша база данных работает на PostgreSQL и этот параметр принимает значение Истина, это сигнал о том, что система работает в режиме совместимости. В некоторых случаях это может привести к тому, что подбор сотрудников в документах или открытие списков будет происходить медленнее, чем на MS SQL Server.

Это связано с тем, что оптимизаторы разных СУБД по-разному строят планы для MAX и для TOP 1. В современных релизах платформы 8.3.15 и выше, а также в свежих версиях PostgreSQL, эта проблема практически нивелирована, но код в ЗУП сохраняется для обеспечения обратной совместимости со старыми серверами или специфическими Linux-дистрибутивами.

Подведем итоги

Мы выяснили, что рассматриваемый «непонятный» код — это элегантный способ платформенной самодиагностики. Основные выводы нашего анализа:

Знание таких тонкостей помогает программисту лучше понимать логику работы типовых конфигураций и диагностировать странные падения запросов в кастомизированных отчетах, особенно при работе в гетерогенных средах (например, при миграции с Windows/MS SQL на Linux/PostgreSQL).

← На главную