При разработке механизмов автоматизации бизнес-процессов в 1С программисты часто сталкиваются со снижением производительности базы данных при выполнении, казалось бы, простых запросов. Типичный сценарий: при открытии документа необходимо проверить, запущен ли по нему бизнес-процесс. Однако простой запрос к таблице бизнес-процессов начинает выполняться чрезвычайно медленно, а у пользователей без полных прав система начинает требовать права на сторонние таблицы (например, на документ «Корректировка регистров»).
В рамках этой статьи мы подробно разберем, почему возникает такая проблема, как платформа 1С обрабатывает запросы на уровне СУБД, и как правильно оптимизировать код, чтобы запрос выполнялся мгновенно и не вызывал ошибок прав доступа.
Рассмотрим исходный запрос, который вызывал существенные задержки в работе системы:
ВЫБРАТЬ РАЗРЕШЕННЫЕ
КОЛИЧЕСТВО(Согласование.Ссылка) КАК КолВо
ИЗ
БизнесПроцесс.CRM_БизнесПроцесс КАК Согласование
ГДЕ
Согласование.Предмет.Ссылка = &ДокСогласование
И Согласование.Ссылка.Дата >= &ДатаСогласования
В этом запросе кроются две серьезные архитектурные ошибки, которые приводят к катастрофическому падению производительности при росте базы данных. Проанализируем каждую из них подробнее.
Главная причина медленной работы и требования прав на документ «Корректировка записей регистров» заключается в конструкции Согласование.Предмет.Ссылка.
Реквизит Предмет у бизнес-процессов практически всегда имеет составной тип данных. В него могут входить десятки или даже сотни различных видов документов и справочников конфигурации. Когда мы обращаемся к свойству составного поля через точку (например, .Ссылка или .Номер), платформа 1С выполняет операцию разыменования.
На уровне СУБД это транслируется в левое соединение (LEFT JOIN) со всеми таблицами, входящими в этот составной тип. Если тип реквизита Предмет включает 100 видов документов, СУБД попытается выполнить левое соединение со всеми 100 таблицами. Это приводит к следующим последствиям:
РАЗРЕШЕННЫЕ убирает ошибку прав доступа, но заставляет платформу накладывать условия RLS на все неявно присоединенные таблицы. В итоге SQL-запрос превращается в огромную конструкцию с сотнями подзапросов, выполнение которой может занимать минуты.Вторая ошибка содержится в строке Согласование.Ссылка.Дата >= &ДатаСогласования.
Поле Ссылка является уникальным идентификатором самой таблицы БизнесПроцесс.CRM_БизнесПроцесс, к которой мы обращаемся в секции ИЗ. Обращаясь к реквизиту Дата через Ссылка.Дата, мы заставляем платформу выполнять дополнительное неявное соединение таблицы саму с собой. Это избыточная операция, которая также увеличивает время выполнения запроса.
Для того чтобы исправить ситуацию, нам необходимо переписать условия в секции ГДЕ, избегая неявных соединений.
Шаг 1. Переходим на прямое сравнение ссылок.
Вместо обращения Согласование.Предмет.Ссылка = &ДокСогласование мы должны использовать прямое сравнение: Согласование.Предмет = &ДокСогласование.
Почему это работает быстро? Параметр &ДокСогласование имеет строго определенный тип (например, ДокументСсылка.Согласование). Платформа 1С анализирует тип передаваемого параметра и на уровне SQL сразу выполняет фильтрацию по идентификатору и коду типа, полностью избегая соединений со всеми остальными таблицами составного типа.
Шаг 2. Исключаем обращение через Ссылка для собственных реквизитов.
Заменяем конструкцию Согласование.Ссылка.Дата на прямое обращение к полю: Согласование.Дата. Поскольку поле Дата физически находится в той же таблице, СУБД получит данные мгновенно без дополнительных соединений.
Посмотрим на оптимизированный вариант запроса:
ВЫБРАТЬ РАЗРЕШЕННЫЕ
КОЛИЧЕСТВО(Согласование.Ссылка) КАК КолВо
ИЗ
БизнесПроцесс.CRM_БизнесПроцесс КАК Согласование
ГДЕ
Согласование.Предмет = &ДокСогласование
И Согласование.Дата >= &ДатаСогласования
Этот простой шаг позволяет сократить время выполнения запроса с нескольких секунд (или даже минут) до сотых долей секунды.
Рассмотрим другие полезные практики, которые необходимо применять при работе со сложными запросами и составными типами данных.
Бывают ситуации, когда вам действительно необходимо получить какой-то специфический реквизит из составного поля (например, прочитать дату документа-предмета, который лежит в реквизите Предмет). Напрямую писать Согласование.Предмет.Дата категорически запрещено.
В таких случаях необходимо использовать функцию ВЫРАЗИТЬ, чтобы явно указать платформе, к какой таблице нужно обратиться:
ВЫБРАТЬ
Согласование.Ссылка,
ВЫРАЗИТЬ(Согласование.Предмет КАК Документ.Согласование).Дата КАК ДатаДокумента
ИЗ
БизнесПроцесс.CRM_БизнесПроцесс КАК Согласование
ГДЕ
Согласование.Предмет ССЫЛКА Документ.Согласование
Использование ВЫРАЗИТЬ сообщает платформе, что левое соединение нужно сделать только с одной конкретной таблицей — Документ.Согласование. Все остальные таблицы составного типа будут проигнорированы, что сохранит высокую скорость работы СУБД.
Часто в типовых и доработанных конфигурациях разработчики оставляют состав типов определяемых типов (таких как ПредметПроцесса) избыточным. Туда могут по умолчанию включаться абсолютно все документы системы.
Рекомендуется регулярно проводить аудит таких типов данных в конфигураторе и исключать из них «тяжелые» технические документы (корректировки регистров, закрытия месяца, расчеты себестоимости), которые никогда не будут выступать в качестве предмета бизнес-процесса. Это существенно упростит SQL-структуру базы данных и ускорит работу всей системы в целом.