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