Работа с временными таблицами (ВТ) — это фундаментальный навык оптимизации запросов в системе 1С:Предприятие 8. Однако начинающие разработчики часто сталкиваются с ситуацией, когда при отладке или попытке получить данные из созданной таблицы они видят пустой результат или вовсе не находят таблицу. Разберем по шагам, как устроены временные таблицы, почему свойство ВременныеТаблицыЗапроса может вводить в заблуждение и как правильно организовать работу с менеджером временных таблиц.
Проанализируем базовый механизм. Временная таблица — это объект, который физически создается в базе данных (в СУБД это чаще всего база tempdb). Существует два основных сценария её «жизни»:
Выполнить(): Если вы создаете ВТ внутри пакета запросов и не используете внешний менеджер, таблица существует ровно столько времени, сколько выполняется метод. Как только управление возвращается в код 1С, таблица в СУБД уничтожается.МенеджерВременныхТаблиц: В этом случае время жизни ВТ привязывается к жизни объекта менеджера в памяти сервера 1С. Пока жив объект или пока не вызван метод Закрыть(), данные остаются доступными для последующих запросов.Выясним причину, по которой данные не видны в отладчике. Если мы просто написали запрос с конструкцией ПОМЕСТИТЬ, но не инициализировали МенеджерВременныхТаблиц, то после выполнения строки Запрос.Выполнить() обращаться к таблицам уже поздно — их больше нет.
Рассмотрим, как правильно подготовить объект Запрос. Существует несколько способов назначить менеджер, но важно соблюдать культуру написания кода и следить за использованием оперативной памяти. Посмотрим на наиболее лаконичный и правильный вариант:
Запрос = Новый Запрос;
// Назначаем новый менеджер напрямую свойству запроса
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ
| 1 КАК ЧисловоеПоле,
| ""Текст"" КАК ТекстовоеПоле
|ПОМЕСТИТЬ ВТ_Тестовая
|;
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| *
|ИЗ
| ВТ_Тестовая КАК ВТ_Тестовая";
РезультатЗапроса = Запрос.Выполнить();
Обратим внимание на важный нюанс: создание отдельной переменной для менеджера (например, МВТ = Новый МенеджерВременныхТаблиц) оправдано только в том случае, если вы планируете передавать этот менеджер в другие процедуры или назначать его разным объектам Запрос. Если же менеджер нужен только для текущего блока кода, прямое присвоение Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц выглядит чище и избавляет от лишних ссылок в памяти.
Часто программисты пытаются найти данные в свойстве Запрос.ВременныеТаблицыЗапроса. Проанализируем это свойство: на самом деле оно является служебным и содержит лишь описание структуры таблиц, а не их строки. Чтобы действительно увидеть данные «здесь и сейчас» при остановке в отладчике, воспользуемся следующими приемами.
Способ 1. Использование ВыполнитьПакетСПромежуточнымиДанными(). Это самый мощный инструмент для отладки. Вместо обычного метода Выполнить(), который возвращает результат только последней выборки, этот метод возвращает массив результатов всех запросов пакета, включая содержимое всех созданных ВТ.
// В табло отладчика или в коде для тестирования
МассивРезультатов = Запрос.ВыполнитьПакетСПромежуточнымиДанными();
// Теперь в МассивРезультатов[0] будут данные первой ВТ, в [1] — второй и т.д.
Важно: Не используйте этот метод в рабочем коде для обработки огромных массивов данных (сотни тысяч строк), так как это заставляет сервер 1С выкачивать абсолютно все данные из СУБД в оперативную память, что может привести к существенному замедлению системы.
Способ 2. Программная выгрузка из менеджера. Если у запроса установлен менеджер, мы можем в любой момент обратиться к нему и выгрузить данные конкретной таблицы в ТаблицуЗначений. Рассмотрим пример:
КоличествоТаблиц = Запрос.МенеджерВременныхТаблиц.Таблицы.Количество();
Сообщить("Всего временных таблиц: " + КоличествоТаблиц);
// Выгружаем данные первой таблицы по индексу
ДанныеВТ = Запрос.МенеджерВременныхТаблиц.Таблицы[0].ПолучитьДанные().Выгрузить();
// Или находим таблицу по имени
ТаблицаПоИмени = Запрос.МенеджерВременныхТаблиц.Таблицы.Найти("вт_Позиция").ПолучитьДанные().Выгрузить();
Рассмотрим ситуацию, когда в запросе используется ОБЪЕДИНИТЬ ВСЕ при помещении данных во временную таблицу. Проанализируем пример кода, который часто вызывает вопросы:
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ 1 КАК Поле ПОМЕСТИТЬ ВТ
|ОБЪЕДИНИТЬ ВСЕ
|ВЫБРАТЬ 2
|;
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ * ИЗ ВТ";
// После выполнения в ВТ будет 2 строки.
// Но если вы смотрите результат в отладчике до выполнения второго запроса в пакете,
// вы можете увидеть некорректное состояние.
Результат = Запрос.Выполнить();
Помните, что ОБЪЕДИНИТЬ ВСЕ внутри конструкции ПОМЕСТИТЬ работает как единая операция. Все части объединения будут помещены в одну таблицу ВТ. Если же вы используете разные пакеты (разделенные точкой с запятой), то данные будут добавляться или перезаписываться в зависимости от текста запроса.
Проанализируем дополнительные технические нюансы, которые помогут сделать работу с ВТ эффективнее:
JOIN), обязательно добавляйте ИНДЕКСИРОВАТЬ ПО.... Это создаст индекс в tempdb и на порядки ускорит выполнение последующих частей пакета.УНИЧТОЖИТЬ ИмяВТ в тексте запроса. Это освободит место в базе временных таблиц СУБД.Закрыть(): Всегда явно закрывайте менеджер, если он был создан как переменная модуля или реквизит формы, чтобы не блокировать ресурсы сервера МенеджерВТ.Закрыть();.Выясним последовательность действий, если вы не видите таблицу:
Запрос.МенеджерВременныхТаблиц.Выполнить() был вызван).Запрос.МенеджерВременныхТаблиц.Таблицы для проверки количества существующих ВТ.ПолучитьДанные().Выгрузить() в окне вычисления выражений.&Ссылка, &Сотрудник) установлены верно, иначе запрос ВЫБРАТЬ...ПОМЕСТИТЬ может просто не найти данных для помещения, и таблица останется физически существующей, но пустой.Таким образом, правильное использование МенеджерВременныхТаблиц и методов ВыполнитьПакетСПромежуточнымиДанными() позволяет полностью контролировать процесс формирования данных и оперативно находить ошибки в сложной логике запросов.