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