К статье
Практический материал

Разработка и Конфигурация · 12 мин

Временные таблицы в 1С: зачем они нужны и как с ними работать

Зачем нужны временные таблицы в запросах 1С, как их создавать через менеджер временных таблиц, типичные ошибки и примеры кода для разработчика.

Временная таблица в запросе 1С — это промежуточный набор данных, который существует только в рамках выполнения запроса или пакета запросов и не сохраняется в базе данных. Она создаётся конструкцией «ПОМЕСТИТЬ ИмяТаблицы», живёт в памяти сервера СУБД и автоматически уничтожается после завершения работы или по команде «УНИЧТОЖИТЬ». Для разработчика это один из главных инструментов оптимизации: вместо одного громоздкого запроса с вложенными подзапросами логика разбивается на понятные этапы.

Без временных таблиц сложные выборки приходится строить через вложенные запросы, которые трудно читать, отлаживать и которые платформа не всегда оптимизирует эффективно. Временная таблица позволяет один раз отобрать нужные данные, а затем многократно использовать их в последующих запросах пакета — для соединений, фильтрации, группировки. Это сокращает и объём кода, и нагрузку на сервер.

Типичный сценарий: нужно получить остатки по списку товаров, переданному из формы или табличной части документа. Напрямую передать список в условие виртуальной таблицы нельзя — но можно поместить список во временную таблицу и соединиться с ней. Именно такие задачи и составляют основу практического применения механизма.

Что такое временная таблица и как она устроена

Физически временная таблица — это таблица, которую платформа 1С создаёт на стороне СУБД (в tempdb для MS SQL Server или аналогичном механизме других СУБД). Она доступна только в рамках своего менеджера временных таблиц: другие сеансы и другие запросы её не видят. После закрытия менеджера все созданные в нём таблицы удаляются автоматически.

Создаётся таблица просто: в тексте запроса после списка полей указывается предложение «ПОМЕСТИТЬ» с именем таблицы. Например, выборка номенклатуры с отбором по виду помещается во временную таблицу «ВТ_Товары», а следующий запрос пакета уже обращается к ней как к обычной таблице через «ИЗ ВТ_Товары». Имя должно быть уникальным в пределах пакета и не совпадать с именами таблиц базы данных.

Важно понимать различие между временной таблицей и вложенным запросом. Вложенный запрос вычисляется каждый раз при обращении к нему, а временная таблица материализуется один раз. Если промежуточный результат используется в пакете дважды и более — временная таблица почти всегда выигрывает по производительности.

Основные задачи, которые решают временные таблицы

Первая и самая частая задача — передача данных из кода в запрос. Таблицу значений, сформированную программно (список контрагентов, отобранные документы, данные из файла), нельзя вставить в текст запроса напрямую. Решение: передать таблицу значений как параметр запроса, поместить её во временную таблицу и дальше работать с ней через соединения и условия.

Вторая задача — оптимизация обращений к виртуальным таблицам. Виртуальные таблицы регистров (Остатки, Обороты, СрезПоследних) строятся платформой динамически, и если наложить отбор не в параметрах виртуальной таблицы, а в секции ГДЕ итогового запроса, СУБД может сначала вычислить всю виртуальную таблицу, а потом фильтровать. Правильный приём: сначала поместить список нужных измерений во временную таблицу, а затем использовать её в параметрах виртуальной таблицы или через соединение.

Третья задача — поэтапная обработка данных. Когда результат нужно получить через несколько логических шагов (отобрать документы → собрать их движения → сгруппировать → обогатить данными справочников), каждый шаг оформляется отдельным запросом пакета с промежуточными временными таблицами. Такой код легко отлаживать: любой промежуточный этап можно вывести в консоли запросов и проверить.

Данные из кодаТаблица значений, список значений

Передать как параметр и поместить во временную таблицу

Повторное использованиеОдин результат нужен в 2+ запросах пакета

Материализовать один раз вместо повторных вычислений

Виртуальные таблицыОстатки, обороты, срезы

Отбор через временную таблицу в параметрах

Сложная логикаНесколько этапов обработки

Разбить на читаемые шаги пакета

Как создать временную таблицу: пошаговый пример

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

Порядок действий
  1. 1
    Создайте объект Запрос и объект МенеджерВременныхТаблиц, присвойте менеджер свойству Запрос.МенеджерВременныхТаблиц
  2. 2
    Передайте таблицу значений в параметр запроса: Запрос.УстановитьПараметр(Товары, ТаблицаТоваров)
  3. 3
    В тексте запроса напишите: ВЫБРАТЬ Товары.Номенклатура ПОМЕСТИТЬ ВТ_Товары ИЗ &Товары КАК Товары
  4. 4
    Добавьте индекс при необходимости: ИНДЕКСИРОВАТЬ ПО Номенклатура
  5. 5
    В следующем запросе пакета соедините ВТ_Товары с виртуальной таблицей остатков
  6. 6
    Выполните пакет методом Запрос.Выполнить() или ВыполнитьПакет() и обработайте результат

Ключевой момент — индексирование. Если временная таблица будет участвовать в соединениях, добавьте в конец первого запроса конструкцию «ИНДЕКСИРОВАТЬ ПО» с полями соединения. На больших объёмах данных это даёт кратный прирост скорости, потому что СУБД сможет использовать поиск по индексу вместо полного перебора.

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

Обратите внимание: отбор по списку товаров наложен прямо в параметрах виртуальной таблицы «Остатки» через вложенный запрос к ВТ_Товары. Это гарантирует, что СУБД вычислит остатки только по нужной номенклатуре, а не по всему регистру.

Менеджер временных таблиц: правила жизненного цикла

Все временные таблицы привязаны к менеджеру. Если создать запрос без менеджера и выполнить ПОМЕСТИТЬ, платформа создаст временный менеджер на время выполнения — и таблица исчезнет сразу после него. Поэтому для пакетов из нескольких запросов менеджер создают явно и назначают каждому запросу, который должен видеть общие таблицы.

Один менеджер можно передавать нескольким объектам Запрос. Это удобно, когда пакет логически разбит на отдельные процедуры: каждая процедура создаёт свой объект Запрос, но получает общий менеджер параметром. Так реализуется модульная архитектура сложных выборок без дублирования данных.

Ещё одно правило: имена временных таблиц в одном менеджере должны быть уникальны. Попытка поместить данные в уже существующую таблицу вызовет ошибку. Если логика требует перезаписи — сначала выполните УНИЧТОЖИТЬ, затем повторное ПОМЕСТИТЬ.

Типичные ошибки при работе с временными таблицами

Самая распространённая ошибка — отбор в секции ГДЕ вместо параметров виртуальной таблицы. Запрос работает, но медленно: сначала строится срез по всему регистру, потом отбрасывается лишнее. На тестовой базе это незаметно, на рабочей с миллионами записей запрос может выполняться минутами.

Вторая ошибка — отсутствие индексов на временных таблицах, участвующих в соединениях. По умолчанию платформа может создать индекс автоматически, но явное указание «ИНДЕКСИРОВАТЬ ПО» делает поведение предсказуемым и управляемым.

Типичные ошибки
01
Отбор по виртуальной таблице в ГДЕ вместо параметров — полное сканирование регистра
02
Отсутствие ИНДЕКСИРОВАТЬ ПО на полях соединения — медленные соединения на больших выборках
03
Помещение во временную таблицу лишних полей — лишний расход памяти и tempdb
04
Забытый УНИЧТОЖИТЬ в цикле — раздувание tempdb и деградация сервера
05
Повторное ПОМЕСТИТЬ в существующее имя — ошибка выполнения запроса
06
Выбор всех полей (ВЫБРАТЬ *) во временную таблицу — неявный состав полей и лишние данные

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

Производительность: когда временная таблица помогает, а когда вредит

Временная таблица — не универсальное ускорение. Материализация данных стоит ресурсов: запись в tempdb, создание индексов. Если промежуточный результат используется один раз и объём его невелик, простой вложенный запрос или соединение могут оказаться быстрее и проще.

Выгода появляется в трёх случаях: промежуточный результат используется многократно; нужен индекс для быстрых соединений; требуется сузить данные перед обращением к тяжёлой виртуальной таблице. Во всех остальных ситуациях стоит сравнить оба варианта на реальных данных через замер времени выполнения.

Временная таблица или вложенный запрос

Временная таблица

Подходит при многократном использовании результата, соединениях по индексу, передаче таблиц значений. Ограничение: расход tempdb и время на материализацию.

Вложенный запрос

Подходит для одноразовых простых выборок небольшого объёма. Ограничение: вычисляется при каждом обращении, хуже читается при вложенности.

Пакет с несколькими ВТ

Подходит для многоэтапной логики и отладки. Ограничение: требует дисциплины с уничтожением таблиц.

Как проверить результат и отладить пакет запросов

Главный инструмент отладки — консоль запросов (внешняя обработка, широко используемая разработчиками) либо пошаговое выполнение в коде: вместо одного ВыполнитьПакет() выполняйте запросы по одному и выгружайте промежуточные таблицы через «ВЫБРАТЬ * ИЗ ВТ_Имя». Так видно, на каком этапе данные теряются или искажаются.

Для оценки производительности полезен план запроса на стороне СУБД. Признаки проблем — операции полного сканирования (Table Scan) по регистрам там, где ожидался поиск по индексу, и большое число логических чтений. Обычно это сигнал перенести отбор в параметры виртуальной таблицы или добавить индекс на временную таблицу.

Контрольные точки

Как проверить результат

Состав временной таблицы
Норма

Только нужные поля и строки, отобранные на этапе

Тревожный признак

Лишние поля, дубли строк, полный набор данных справочника

План запроса на СУБД
Норма

Index Seek по полям соединения

Тревожный признак

Table Scan по регистру накопления

Содержимое tempdb после цикла
Норма

Таблицы уничтожаются по мере завершения этапов

Тревожный признак

Накопление десятков ВТ и рост tempdb

Время выполнения
Норма

Сопоставимо с объёмом отобранных данных

Тревожный признак

Запрос растёт пропорционально размеру всего регистра

Часто задаваемые вопросы

Чем временная таблица отличается от таблицы значений?

Таблица значений — объект встроенного языка, живёт в памяти сервера 1С и обрабатывается кодом. Временная таблица — объект на стороне СУБД, доступный только внутри запросов. Таблицу значений можно передать в запрос как параметр и превратить во временную таблицу конструкцией ПОМЕСТИТЬ.

Сколько временных таблиц можно создать в одном запросе?

Жёсткого ограничения платформы на количество таблиц в пакете нет, но каждая таблица расходует память и место в tempdb. На практике пакеты из 3–10 таблиц считаются нормой; если их становятся десятки, стоит пересмотреть архитектуру и уничтожать промежуточные таблицы сразу после использования.

Нужно ли явно уничтожать временные таблицы?

После завершения работы менеджера таблицы удаляются автоматически, поэтому в коротких разовых операциях УНИЧТОЖИТЬ не обязателен. Но в циклах, длительных фоновых заданиях и при больших объёмах явное уничтожение ненужных таблиц защищает tempdb от разрастания и считается хорошей практикой.

Почему запрос с временной таблицей работает медленно?

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

Можно ли использовать одну временную таблицу в разных объектах Запрос?

Да, если всем этим объектам назначен один и тот же МенеджерВременныхТаблиц. Именно так строят модульные выборки: каждая процедура работает со своим объектом Запрос, но видит общие временные таблицы через общий менеджер.

Что произойдёт, если дважды выполнить ПОМЕСТИТЬ с одним именем?

Платформа выдаст ошибку о том, что таблица уже существует. Чтобы перезаписать временную таблицу, сначала выполните в пакете оператор УНИЧТОЖИТЬ с её именем, а затем повторное ПОМЕСТИТЬ.

Итог

Что важно запомнить

Временные таблицы нужны для передачи данных из кода в запрос, поэтапной обработки и ускорения обращений к виртуальным таблицам. Создавайте их через ПОМЕСТИТЬ с явным менеджером, индексируйте поля соединений, накладывайте отборы в параметрах виртуальных таблиц и уничтожайте ненужные таблицы в длительных операциях.