Насколько корректно брать данные из регистра накопления (обороты) без выбора ресурсов?

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

При разработке на платформе «1С:Предприятие» часто возникает задача проверить сам факт наличия записи в регистре накопления за определенный период. Типичный пример — проверка, был ли сотрудник на больничном в конкретный день, используя данные регистра ДанныеТабельногоУчетаРабочегоВремениСотрудников в конфигурации «Зарплата и управление персоналом». Рассмотрим ситуацию, когда программист обращается к виртуальной таблице .Обороты, но выбирает в секции ВЫБРАТЬ только измерения (например, Сотрудник) и периоды (День), полностью игнорируя ресурсы (Часы, Дни и т.д.).

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

Анализ работы виртуальной таблицы оборотов

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

Когда мы пишем запрос к РегистрНакопления.ИмяРегистра.Обороты(...), платформа генерирует сложный SQL-запрос. Если мы не выбираем ресурсы, СУБД все равно вынуждена выполнять операцию группировки (GROUP BY) по всем измерениям, указанным в параметрах виртуальной таблицы, и по полям периодичности. Если наша цель — просто узнать факт наличия записи, то выполнение тяжелой операции группировки на стороне сервера SQL является избыточным расходом ресурсов.

Рассмотрим пример запроса, который вызывает сомнения:


Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
               |    ДанныеТабельногоУчета.Сотрудник КАК Сотрудник,
               |    ДанныеТабельногоУчета.Период КАК День
               |ИЗ
               |    РегистрНакопления.ДанныеТабельногоУчетаРабочегоВремениСотрудников.Обороты(
               |        &НачалоПериода,
               |        &КонецПериода,
               |        День,
               |        ВидУчетаВремени = &ВидУчетаВремени) КАК ДанныеТабельногоУчета";

В данном случае использование виртуальной таблицы .Обороты с периодичностью День заставляет систему выполнять лишнюю работу. Проанализируем почему.

Проблема периодичности и итогов

Основное преимущество виртуальных таблиц оборотов заключается в использовании механизма предварительно рассчитанных итогов. Эти итоги в 1С обычно хранятся с периодичностью «Месяц».

  1. Если период вашего запроса кратен месяцу, платформа может быстро прочитать данные из таблицы итогов.
  2. Если же вы указываете периодичность День (как в примере выше), платформа вынуждена обращаться к основной (физической) таблице движений регистра, чтобы «дособрать» данные за конкретные дни, которые не кратны месяцу.

Таким образом, выбирая периодичность День, мы лишаем себя главного преимущества виртуальной таблицы (скорости итогов), но при этом оставляем накладные расходы на построение самой виртуальной таблицы платформой. В итоге запрос работает медленнее, чем прямое обращение к физической таблице.

Решение 1: Обращение к физической таблице движений

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


Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ РАЗЛИЧНЫЕ
               |    Табель.Сотрудник КАК Сотрудник,
               |    Табель.Период КАК День
               |ИЗ
               |    РегистрНакопления.ДанныеТабельногоУчетаРабочегоВремениСотрудников КАК Табель
               |ГДЕ
               |    Табель.Период МЕЖДУ &НачалоПериода И &КонецПериода
               |    И Табель.ВидУчетаВремени = &ВидУчетаВремени";

Разберем преимущества этого подхода:

Решение 2: Проверка факта через ВЫБРАТЬ 1

Если в коде нам не нужно получать список сотрудников или дат, а требуется лишь проверить, существует ли вообще хоть одна запись по заданным критериям (например, в рамках проверки в подписке на событие), можно использовать еще более оптимизированный вариант:


Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1
               |    1
               |ИЗ
               |    РегистрНакопления.ДанныеТабельногоУчетаРабочегоВремениСотрудников КАК Табель
               |ГДЕ
               |    Табель.Сотрудник = &Сотрудник
               |    И Табель.Период = &НужнаяДата
               |    И Табель.ВидУчетаВремени = &ВидУчетаВремени";

Если НЕ Запрос.Выполнить().Пустой() Тогда
    // Факт зафиксирован, выполняем логику
КонецЕсли;

Использование ВЫБРАТЬ ПЕРВЫЕ 1 вместе с обращением к физической таблице — это самый быстрый способ проверки существования данных в 1С.

Когда все же стоит использовать виртуальную таблицу?

Несмотря на вышесказанное, бывают ситуации, когда использование .Обороты без ресурсов оправдано:

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

Проанализировав ситуацию, мы пришли к следующим выводам:

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

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

← На главную