При изучении программного кода типовой конфигурации «Зарплата и управление персоналом», редакция 3.1, программисты часто натыкаются на необычную конструкцию в модуле сеанса или в процедурах установки параметров сеанса. На первый взгляд запрос выглядит избыточным и даже странным: создается временная таблица из одного числа, а затем к ней выполняется запрос с вложенным подзапросом, который делает практически то же самое. В этой статье мы подробно разберем, зачем разработчики фирмы «1С» используют такой подход и какие технические задачи это решает.
Рассмотрим фрагмент кода, который вызывает вопросы. Этот участок кода выполняется при инициализации параметра сеанса АльтернативныйПодборСпискаСотрудников. Проанализируем его структуру:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| 1 КАК Номер
|ПОМЕСТИТЬ ВТТестируемаяТаблица
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ТестируемаяТаблица.Номер КАК Номер
|ИЗ
| ВТТестируемаяТаблица КАК ТестируемаяТаблица
|ГДЕ
| ТестируемаяТаблица.Номер В
| (ВЫБРАТЬ ПЕРВЫЕ 1
| ТестируемаяТаблицаОтбор.Номер
| ИЗ
| ВТТестируемаяТаблица КАК ТестируемаяТаблицаОтбор
| ГДЕ
| ТестируемаяТаблицаОтбор.Номер = ТестируемаяТаблица.Номер
| УПОРЯДОЧИТЬ ПО
| ТестируемаяТаблицаОтбор.Номер)";
Попытка
Запрос.Выполнить();
АльтернативныйПодбор = Ложь;
Исключение
АльтернативныйПодбор = Истина;
КонецПопытки;
На первый взгляд, этот запрос всегда должен возвращать единицу и выполняться успешно. Однако ключевым моментом здесь является блок Попытка...Исключение. Смысл этого кода не в получении данных, а в проверке самой возможности выполнения такой синтаксической конструкции на конкретном сервере СУБД.
Проанализируем ситуацию: платформа 1С является кроссплатформенной и работает с различными СУБД (MS SQL Server, PostgreSQL, Oracle, IBM DB2). Каждая из этих систем имеет свои особенности реализации стандарта SQL. Метод, представленный в коде, называется feature detection (определение возможностей). Вместо того чтобы проверять версию СУБД или её название, система просто пробует выполнить «проблемный» запрос. Если он падает с ошибкой — значит, данная СУБД не поддерживает такую логику, и нужно использовать обходной путь.
Выясним причину, по которой этот код вообще появился. Основная цель данной проверки — выявить ограничения некоторых версий СУБД PostgreSQL. Проблема заключается в использовании конструкции ВЫБРАТЬ ПЕРВЫЕ 1 (аналог LIMIT 1) совместно с УПОРЯДОЧИТЬ ПО (ORDER BY) внутри коррелированного подзапроса.
Коррелированный подзапрос — это подзапрос, который обращается к полям внешней таблицы (в нашем примере это условие ГДЕ ТестируемаяТаблицаОтбор.Номер = ТестируемаяТаблица.Номер). Некоторые сборки PostgreSQL некорректно обрабатывают такие конструкции, если в них присутствует сортировка, или выдают крайне неоптимальный план выполнения, что может привести к критической ошибке или зависанию рабочего процесса.
Давайте посмотрим, как результат этой проверки влияет на дальнейшую работу программы. В ЗУП 3.1 параметр сеанса АльтернативныйПодборСпискаСотрудников используется при построении динамических списков сотрудников и в механизмах RLS (ограничение доступа на уровне записей).
ВЫБРАТЬ ПЕРВЫЕ 1 ... УПОРЯДОЧИТЬ ПО позволяет получить одну конкретную запись по сложному критерию. Например, получить последнюю по дате кадровую перестановку сотрудника. Это позволяет делать очень точные выборки.ВЫБРАТЬ МАКСИМУМ(ИмяПоля).Рассмотрим разницу на примере логики запроса. Допустим, нам нужно найти последнее подразделение сотрудника. Основной вариант будет выглядеть примерно так:
ГДЕ Подразделение В (ВЫБРАТЬ ПЕРВЫЕ 1 Т.Подразделение ИЗ Таблица КАК Т ГДЕ Т.Сотрудник = ОсновнаяТаблица.Сотрудник УПОРЯДОЧИТЬ ПО Т.Период УБЫВ)
А альтернативный вариант, который гарантированно сработает на любой СУБД, заменит это на:
ГДЕ Подразделение В (ВЫБРАТЬ МАКСИМУМ(Т.Подразделение) ИЗ Таблица КАК Т ГДЕ Т.Сотрудник = ОсновнаяТаблица.Сотрудник)
Важный нюанс: использование МАКСИМУМ не всегда идентично ПЕРВЫЕ 1 с сортировкой по дате, поэтому разработчики 1С применяют этот метод только тогда, когда это допустимо с точки зрения бизнес-логики, или когда другого способа избежать ошибки СУБД просто нет.
Проанализируем ситуацию с точки зрения системного администратора. Если ваша база данных работает на PostgreSQL и этот параметр принимает значение Истина, это сигнал о том, что система работает в режиме совместимости. В некоторых случаях это может привести к тому, что подбор сотрудников в документах или открытие списков будет происходить медленнее, чем на MS SQL Server.
Это связано с тем, что оптимизаторы разных СУБД по-разному строят планы для MAX и для TOP 1. В современных релизах платформы 8.3.15 и выше, а также в свежих версиях PostgreSQL, эта проблема практически нивелирована, но код в ЗУП сохраняется для обеспечения обратной совместимости со старыми серверами или специфическими Linux-дистрибутивами.
Мы выяснили, что рассматриваемый «непонятный» код — это элегантный способ платформенной самодиагностики. Основные выводы нашего анализа:
АльтернативныйПодборСпискаСотрудников напрямую влияет на то, какой текст SQL будет сгенерирован платформой для получения кадровых данных.Знание таких тонкостей помогает программисту лучше понимать логику работы типовых конфигураций и диагностировать странные падения запросов в кастомизированных отчетах, особенно при работе в гетерогенных средах (например, при миграции с Windows/MS SQL на Linux/PostgreSQL).