Разработка и Конфигурация · 11 мин
Как создать менеджер временных таблиц в 1С
Пошаговая инструкция по созданию менеджера временных таблиц в 1С: код на встроенном языке, передача между запросами, типичные ошибки и проверка результата.
Менеджер временных таблиц в 1С — это объект встроенного языка, который хранит результаты запросов в виде именованных временных таблиц и позволяет использовать их в последующих запросах без повторного обращения к базе данных. Он незаменим, когда сложную выборку нужно разбить на этапы: сначала отобрать и сгруппировать данные, затем соединить промежуточный результат с другими таблицами.
Типичный сценарий — отчёт, где сначала формируется таблица остатков, потом она соединяется с оборотами, а затем с ценами. Без менеджера временных таблиц пришлось бы либо строить громоздкий запрос с множеством вложенных подзапросов, либо выгружать промежуточные данные в таблицы значений и передавать их параметрами. Оба варианта медленнее и труднее в сопровождении.
Ниже разобрано, как программно создать менеджер временных таблиц, помещать в него данные, передавать его между процедурами и проверять корректность работы. Все примеры ориентированы на управляемое приложение, но подходят и для обычных форм.
Что такое менеджер временных таблиц и когда он нужен
Менеджер временных таблиц (объект типа МенеджерВременныхТаблиц) — это контейнер, в котором платформа хранит временные таблицы, созданные запросами с конструкцией ПОМЕСТИТЬ ИмяТаблицы. Пока менеджер существует, любой запрос, связанный с ним, может обращаться к этим таблицам по имени, как к обычным таблицам базы данных.
Физически временные таблицы размещаются в служебной базе tempdb СУБД (в клиент-серверном варианте) или во временном хранилище файловой базы. Они живут, пока жив менеджер: после уничтожения объекта или вызова метода Закрыть() все временные таблицы удаляются.
Использовать менеджер стоит, когда выполняется хотя бы одно из условий: запрос логически делится на этапы, промежуточный результат нужен нескольким запросам, или один и тот же отбор используется в пакете запросов. Для одиночного простого запроса менеджер избыточен.
Создание менеджера и привязка к запросу
Создание менеджера — одна строка кода. Далее его нужно присвоить свойству МенеджерВременныхТаблиц каждого запроса, который должен видеть общие временные таблицы. Если свойство не заполнить, запрос выполнится в собственном неявном менеджере, и чужие временные таблицы ему будут недоступны.
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос.Текст =
"ВЫБРАТЬ
| Продажи.Номенклатура КАК Номенклатура,
| СУММА(Продажи.Количество) КАК Количество
|ПОМЕСТИТЬ ВТ_Продажи
|ИЗ
| РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК Продажи
|СГРУППИРОВАТЬ ПО
| Продажи.Номенклатура";
Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
Запрос.УстановитьПараметр("КонецПериода", КонецПериода);
Запрос.Выполнить();
Обратите внимание: при вызове Выполнить() запрос с конструкцией ПОМЕСТИТЬ возвращает результат с количеством помещённых строк, а основная выборка сохраняется в менеджере. Получить данные из временной таблицы можно вторым запросом, привязанным к тому же менеджеру.
- 1Создайте объект: МенеджерВТ = Новый МенеджерВременныхТаблиц
- 2Создайте запрос и присвойте Запрос.МенеджерВременныхТаблиц = МенеджерВТ
- 3В тексте запроса используйте ПОМЕСТИТЬ ИмяТаблицы для сохранения промежуточных данных
- 4Выполните запрос методом Выполнить()
- 5Создайте следующий запрос с тем же менеджером и обратитесь к временной таблице по имени
- 6После завершения работы вызовите МенеджерВТ.Закрыть()
Помещение данных и работа с несколькими запросами
Второй и последующие запросы читают временную таблицу по имени, указанному в ПОМЕСТИТЬ. Имя должно быть уникальным внутри менеджера: попытка поместить таблицу с уже существующим именем вызовет ошибку. Предусмотрите осмысленные имена с префиксом, например ВТ_, чтобы не перепутать временные таблицы с реальными.
Запрос2 = Новый Запрос;
Запрос2.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос2.Текст =
"ВЫБРАТЬ
| ВТ_Продажи.Номенклатура КАК Номенклатура,
| ВТ_Продажи.Количество КАК Количество,
| Цены.Цена КАК Цена
|ИЗ
| ВТ_Продажи КАК ВТ_Продажи
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ) КАК Цены
| ПО ВТ_Продажи.Номенклатура = Цены.Номенклатура";
Результат = Запрос2.Выполнить().Выгрузить();
Один запрос может содержать пакет из нескольких операторов, разделённых точкой с запятой: первый помещает временную таблицу, второй читает её. Это удобно для компактного кода, но затрудняет отладку — при ошибке сложнее понять, на каком этапе она возникла. Для сложной логики предпочтительнее отдельные объекты запросов.
Временную таблицу можно удалить явно конструкцией УНИЧТОЖИТЬ ИмяТаблицы в тексте запроса. Это полезно, когда промежуточные данные больше не нужны, а менеджер продолжает использоваться: освобождается память и место в tempdb.
Передача менеджера между процедурами и внешними источниками
Менеджер временных таблиц — ссылочный объект, поэтому его можно передавать параметром в процедуры и функции общих модулей. Все вызванные процедуры будут работать с одним набором временных таблиц. Это стандартный способ организации многоэтапных расчётов: модуль верхнего уровня создаёт менеджер, а вспомогательные процедуры наполняют его.
Есть и обратная задача — передать во временную таблицу данные, полученные не запросом, а, например, таблицу значений. Для этого таблица значений передаётся параметром запроса, а в тексте используется выборка из параметра: ВЫБРАТЬ Т.Поле ПОМЕСТИТЬ ВТ_Данные ИЗ &ТаблицаЗначений КАК Т.
Передача большой таблицы значений параметром запроса — затратная операция: данные сериализуются и загружаются во временную таблицу СУБД. Если строк десятки тысяч и больше, сравните по времени с вариантом прямого запроса к регистру — часто обращение к базе оказывается быстрее.
Учтите ограничение: менеджер временных таблиц нельзя передать между клиентом и сервером и между сеансами. Он существует только в рамках одного серверного вызова (или клиентского контекста в толстом клиенте). Если данные нужны в другом сеансе, их придётся материализовать — выгрузить в таблицу значений и передать через временное хранилище.
Особенности в СКД и типовых механизмах
В системе компоновки данных менеджер временных таблиц применяется для внешних наборов данных и при программном формировании отчётов. В типовых конфигурациях широко используется общий модуль для работы с временными таблицами (в разных конфигурациях его имя отличается), предоставляющий функции проверки существования таблицы и получения её содержимого.
При программной инициализации СКД менеджер передаётся в процессор компоновки через объект внешних наборов данных или напрямую, если схема использует запрос с временными таблицами. Важно, чтобы менеджер был создан и заполнен до инициализации процессора компоновки — иначе СКД не найдёт нужные таблицы и выдаст ошибку.
Типичные ошибки и их последствия
Самая частая ошибка — обращение к временной таблице из запроса, у которого не заполнено свойство МенеджерВременныхТаблиц. Платформа сообщает, что таблица не найдена, хотя она была создана. Вторая по частоте — повторное помещение таблицы с тем же именем без предварительного УНИЧТОЖИТЬ.
Отдельная группа проблем связана с производительностью. Временная таблица без индексов при соединении с большой таблицей может резко замедлить запрос. В языке запросов предусмотрена конструкция ИНДЕКСИРОВАТЬ ПО после ПОМЕСТИТЬ — используйте её для полей, участвующих в соединениях.
Проверка результата и отладка
Проверить содержимое временной таблицы можно простым запросом: ВЫБРАТЬ * ИЗ ВТ_Продажи с тем же менеджером. В отладчике удобно выгружать результат в таблицу значений и смотреть её через «Вычислить выражение». Так вы убедитесь, что на каждом этапе в таблице именно те строки, которые ожидались.
Для диагностики структуры менеджера используется метод Таблицы — коллекция описаний временных таблиц с именами и списками колонок. Это помогает программно проверить, существует ли нужная таблица, прежде чем обращаться к ней.
Как проверить результат
Все запросы ссылаются на один объект менеджера
У части запросов свойство пустое — временные таблицы им недоступны
Запрос ВЫБРАТЬ * ИЗ ВТ_Имя возвращает ожидаемые строки
Пустой результат или лишние строки — ошибка в условиях помещающего запроса
После работы вызван МенеджерВТ.Закрыть() или применено УНИЧТОЖИТЬ
Менеджер живёт весь сеанс, tempdb растёт
Часто задаваемые вопросы
Чем менеджер временных таблиц отличается от таблицы значений?
Таблица значений — объект в памяти приложения, с ней работают циклами и методами встроенного языка. Временная таблица хранится на стороне СУБД и участвует в запросах: соединениях, группировках, отборах. Для обработки внутри запроса эффективнее временные таблицы, для построчной логики и передачи на клиента — таблицы значений.
Можно ли использовать один менеджер в нескольких потоках или фоновых заданиях?
Нет. Менеджер временных таблиц привязан к текущему сеансу и контексту исполнения. В фоновое задание его передать нельзя — там нужно создать собственный менеджер и заново поместить необходимые данные либо передать их через параметры и временное хранилище.
Что происходит с временными таблицами после закрытия менеджера?
Метод Закрыть() удаляет все временные таблицы, созданные через этот менеджер, и освобождает ресурсы СУБД. Если менеджер не закрыть явно, таблицы будут удалены при уничтожении объекта сборщиком мусора или завершении сеанса, но явное закрытие — хорошая практика для длительных операций.
Как узнать, существует ли временная таблица в менеджере?
Переберите коллекцию МенеджерВТ.Таблицы и сравните имена, либо используйте функции из общих модулей типовой конфигурации, если они есть. Прямого метода «Найти» у коллекции нет, поэтому обычно пишут цикл по элементам с проверкой свойства ПолноеИмя.
Нужно ли индексировать временные таблицы всегда?
Нет. Индексация оправдана, когда временная таблица содержит заметное количество строк и участвует в соединениях или условиях по конкретным полям. Для маленьких таблиц из нескольких десятков строк создание индекса только добавляет накладные расходы без выигрыша в скорости.
Можно ли создать временную таблицу без менеджера?
Да, если выполнить запрос с ПОМЕСТИТЬ без заданного менеджера, платформа создаст неявный менеджер внутри этого объекта запроса. Но обратиться к такой таблице из другого запроса уже нельзя — поэтому для многоэтапной логики всегда создавайте менеджер явно.
Что важно запомнить
Менеджер временных таблиц создаётся одной строкой, привязывается к каждому запросу и хранит таблицы, помещённые конструкцией ПОМЕСТИТЬ. Следите за уникальностью имён, индексируйте большие таблицы по полям соединений и закрывайте менеджер после завершения работы.