Нужно ли вызывать функции НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА в параметрах виртуальных таблиц оборотов?

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

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

Проблема времени 00:00:00 и точность данных

Разберем базовую ситуацию. Если мы передаем в параметр запроса &ДатаКонца значение типа "Дата", которое содержит только число (например, 01.01.2023), то фактически это значение интерпретируется как 01.01.2023 00:00:00. Рассмотрим, что произойдет при обращении к виртуальной таблице оборотов:


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

Если в &ДатаКонца передано начало дня, то все движения, совершенные в течение этого дня (например, продажа в 14:30), не попадут в результат. Платформа воспримет это как требование получить данные строго до первой секунды указанной даты. Чтобы включить в оборот весь день целиком, нам необходимо передать в запрос время 23:59:59. Рассмотрим подробнее, какими способами это можно сделать.

Способ 1. Использование функций в тексте запроса

Первый и самый очевидный способ — использование встроенных функций языка запросов НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА непосредственно в параметрах виртуальной таблицы. Проанализируем пример:


ВЫБРАТЬ
    ПродажиОбороты.СтоимостьОборот
ИЗ
    РегистрНакопления.Продажи.Обороты(
        НАЧАЛОПЕРИОДА(&Дата1, ДЕНЬ), 
        КОНЕЦПЕРИОДА(&Дата2, ДЕНЬ)
    ) КАК ПродажиОбороты

Этот подход гарантирует, что вне зависимости от того, какое время пришло в параметрах &Дата1 и &Дата2, запрос всегда возьмет полный интервал. Однако у этого метода есть существенный недостаток, связанный с оптимизацией. Вычисление функций над параметрами внутри запроса может помешать СУБД эффективно построить план выполнения. СУБД не всегда может заранее определить, что результат функции — это константа, и это может привести к избыточным нагрузкам при сложных соединениях.

Способ 2. Предварительная подготовка параметров (Рекомендуемый)

Наиболее правильным с точки зрения производительности и надежности считается подготовка параметров во встроенном языке 1С перед выполнением запроса. Рассмотрим, как это выглядит в коде:


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

// Приводим даты к началу и концу дня программно
Запрос.УстановитьПараметр("ДатаНачала", НачалоДня(ДатаНачала));
Запрос.УстановитьПараметр("ДатаКонца", КонецДня(ДатаКонца));

Почему это лучше? Выясним причину: когда мы передаем в запрос уже готовое значение, платформа транслирует его в SQL как простой литерал (конкретное значение даты). СУБД видит четкие границы периода и может максимально эффективно использовать индексы таблиц итогов и движений. Это исключает "сканирование" лишних данных и ускоряет выполнение отчета.

Способ 3. Работа с объектом Граница

Иногда возникает вопрос: нужно ли использовать объект Граница для оборотных регистров, как мы это делаем для остатков? Напомним, что для получения остатков на конкретный момент времени с учетом движений самого документа используется конструкция:

Граница(КонецДня(Дата), ВидГраницы.Включая)

Однако для виртуальной таблицы Обороты использование объекта Граница чаще всего является избыточным. Таблица оборотов по своей сути работает с временным интервалом. Если вы передадите в качестве конца периода 23:59:59, платформа автоматически включит все записи, время которых меньше или равно этому значению. Использование Граница допустимо, но не дает никаких преимуществ перед простым использованием КонецДня в случае оборотов.

Особенности работы в Системе компоновки данных (СКД)

Разберем ситуацию, когда отчет строится на СКД. В СКД часто используется стандартный период. Если в параметрах виртуальной таблицы указаны стандартные имена &НачалоПериода и &КонецПериода, система при включенном автозаполнении умеет самостоятельно обрабатывать границы.

Посмотрим на важный нюанс: если пользователь выбирает период "Январь", СКД автоматически подставит 01.01.2023 00:00:00 и 31.01.2023 23:59:59. Но если вы вручную пропишете в тексте запроса КОНЕЦПЕРИОДА(&ДатаКонца, ДЕНЬ), вы можете переопределить поведение системы, что иногда приводит к неожиданным результатам (например, если пользователь намеренно указал время в параметре, а запрос его "сбросил" на конец дня).

Поэтому в СКД рекомендуется:

  1. Использовать стандартные параметры периода.
  2. Если нужны скрытые параметры, вычислять их в выражениях на закладке "Параметры", используя функции языка выражений СКД, а не в самом тексте SQL-запроса.

Технические подробности и SARGability

Проанализируем ситуацию с точки зрения СУБД. Существует понятие SARGable (Search Argumentable) запросов. Это запросы, которые позволяют эффективно использовать индексы. Когда вы пишете ГДЕ КОНЕЦПЕРИОДА(ДатаДокумента, ДЕНЬ) = &Параметр, вы делаете запрос "не-SARGable", так как СУБД должна вычислить функцию для каждой строки таблицы перед сравнением.

Хотя в параметрах виртуальной таблицы 1С старается оптимизировать такие вызовы, правило хорошего тона для разработчика 1С остается прежним: все, что можно вычислить вне запроса, должно быть вычислено вне запроса. Это касается и функций НАЧАЛОПЕРИОДА, КОНЕЦПЕРИОДА, ДОБАВИТЬКДАТЕ и других.

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

Разберем краткий алгоритм действий при работе с периодами оборотов:

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

← На главную