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