При разработке запросов в системе 1С:Предприятие программисты часто сталкиваются с ошибкой "Неверные параметры" при попытке наложить фильтр на поле Регистратор непосредственно внутри параметров виртуальной таблицы (например, Продажи.Обороты). На первый взгляд это кажется нелогичным: если мы можем выбрать это поле в секции ВЫБРАТЬ, почему мы не можем передать его как параметр для оптимизации выборки?
В этой статье мы подробно разберем внутреннее устройство регистров накопления, выясним причины такого поведения платформы и рассмотрим наиболее эффективные способы решения этой задачи.
Для начала проанализируем, как устроены виртуальные таблицы 1С. Когда мы обращаемся к таблице РегистрНакопления.Продажи.Обороты, платформа не просто читает данные из одной таблицы в базе данных SQL. Она пытается максимально оптимизировать запрос, обращаясь к специальным служебным таблицам — таблицам итогов.
Рассмотрим структуру хранения данных в типичном регистре накопления:
Период, Регистратор, НомерСтроки, а также все измерения и ресурсы.Критически важный момент: в таблицах итогов поле Регистратор отсутствует. Итоги хранятся «свернуто». Параметр "Условие" (четвертый параметр виртуальной таблицы Обороты) предназначен для того, чтобы платформа могла наложить фильтр на этапе обращения к таблице итогов. Поскольку регистратора в итогах нет, попытка передать его в параметры вызывает синтаксическую ошибку на уровне парсера запросов 1С.
Часто возникает вопрос: "Но ведь я могу указать периодичность Регистратор, и тогда поле появится в выборке!". Это верно. Рассмотрим пример такого запроса:
|ВЫБРАТЬ
| ПродажиОбороты.Регистратор,
| ПродажиОбороты.СуммаОборот
|ИЗ
| РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, Регистратор, ) КАК ПродажиОбороты
В данном случае, указывая периодичность Регистратор, мы заставляем платформу отказаться от использования быстрых таблиц итогов и перейти к сканированию основной таблицы движений. Однако даже в этом случае платформа сохраняет жесткую структуру параметров виртуальной таблицы: в поле "Условие" допускаются только измерения регистра. Это сделано для унификации программного интерфейса запросов.
Если вам необходимо получить данные именно из виртуальной таблицы (например, вам нужны обороты за период, но ограниченные конкретным документом), стандартным и правильным способом будет использование секции ГДЕ.
Рассмотрим, как это выглядит в коде:
|ВЫБРАТЬ
| ПродажиОбороты.Организация,
| ПродажиОбороты.Номенклатура,
| ПродажиОбороты.СуммаОборот
|ИЗ
| РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, Регистратор, ) КАК ПродажиОбороты
|ГДЕ
| ПродажиОбороты.Регистратор = &Регистратор
Многие опасаются, что ГДЕ работает медленнее, чем фильтр в параметрах. В большинстве случаев это правда для измерений, так как 1С сначала выбирает все данные, а потом фильтрует их. Но для поля Регистратор ситуация иная. Основная таблица движений регистра всегда индексирована по регистратору. СУБД (SQL Server, PostgreSQL) эффективно использует этот индекс, и скорость выполнения запроса будет практически идентичной той, если бы параметр существовал внутри виртуальной таблицы.
Если ваша задача — получить движения одного конкретного документа, то использование виртуальной таблицы Обороты является избыточным (architectural overhead). Виртуальная таблица — это мощный инструмент для расчета итогов за большие периоды. Для данных одного регистратора гораздо эффективнее обращаться напрямую к основной таблице.
Посмотрим на пример правильного обращения к физической таблице:
|ВЫБРАТЬ
| Продажи.Организация КАК Организация,
| Продажи.Контрагент КАК Контрагент,
| Продажи.Номенклатура КАК Номенклатура,
| Продажи.Сумма КАК СуммаОборот
|ИЗ
| РегистрНакопления.Продажи КАК Продажи
|ГДЕ
| Продажи.Регистратор = &Регистратор
Преимущества этого метода:
Index Seek по кластерному индексу таблицы движений.Выясним, в каких ситуациях стоит использовать тот или иной подход. Выбор зависит от того, что именно вы хотите получить в результате.
Ситуация А: Нужно получить данные только по одному регистратору.
Используйте прямой запрос к таблице регистра. Это самый быстрый путь. Виртуальная таблица здесь не нужна, так как нет задачи суммировать данные разных документов.
Ситуация Б: Нужно получить обороты за период, но отфильтрованные по сложному условию, связанному с регистратором (например, по автору документа).
Используйте виртуальную таблицу с периодичностью Регистратор и условием в ГДЕ.
|ВЫБРАТЬ
| ПродажиОбороты.Номенклатура,
| ПродажиОбороты.СуммаОборот
|ИЗ
| РегистрНакопления.Продажи.Обороты(, , Регистратор, ) КАК ПродажиОбороты
|ГДЕ
| ПродажиОбороты.Регистратор.Ответственный = &Ответственный
Ситуация В: Нужно получить итоги по измерениям, но исключить движения определенных регистраторов.
Здесь также используется виртуальная таблица с периодичностью Регистратор, так как нам все еще нужна агрегация по измерениям (например, общая сумма продаж по товару), но с детализацией до документа для выполнения фильтрации.
Стоит также упомянуть периодичность Авто. Если вы используете её в виртуальной таблице, платформа сама определяет необходимый уровень детализации. Если в списке выбранных полей (ВЫБРАТЬ) есть Регистратор или Период, 1С автоматически поднимет уровень детализации до регистратора. Однако правило параметров остается неизменным: отбор по регистратору в скобках все равно будет вызывать ошибку.
Подводя итог нашему анализу, закрепим основные правила работы с регистратором в запросах:
РегистрНакопления.ИмяРегистра).Соблюдение этих простых принципов позволит вам писать чистый, производительный код и избегать досадных ошибок при работе с механизмом запросов 1С.