Язык запросов 1С:Предприятия 8 позволяет использовать временные таблицы в запросах. Использование временных таблиц помогает повысить производительность запросов и сделать текст сложных запросов более легким для восприятия.

Работа с временными таблицами обеспечивается двумя составляющими:

Объектом встроенного языка МенеджерВременныхТаблиц, который хранит в себе данные временных таблиц;
синтаксисом языка запросов, позволяющим создавать новые временные таблицы и использовать существующие временные таблицы.
Менеджер временных таблиц
Менеджер временных таблиц предназначен для управления временем жизни временных таблиц, создаваемых в процессе работы прикладного решения.

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

Экземпляр менеджера временных таблиц может быть создан с помощью конструктора Новый. Например:

Все временные таблицы, созданные в данном экземпляре менеджера, существуют до тех пор, пока существует сам экземпляр менеджера временных таблиц. При уничтожении экземпляра менеджера все временные таблицы, содержащиеся в нем, также удаляются.

Менеджер временных таблиц можно закрыть принудительно при помощи метода Закрыть(). При этом будут удалены все созданные в нем таблицы. Дальнейшая работа с данным экземпляром менеджера будет невозможна.

Создание временных таблиц
Создание временных таблиц осуществляется с помощью объекта Запрос встроенного языка 1С:Предприятия 8.

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

МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;

Временная таблица может быть создана на основе данных базы данных или на основе внешнего источника данных (например, таблицы значений).

Для того чтобы создать временную таблицу на основе данных базы данных, следует установить объекту Запрос менеджер временных таблиц, а затем выполнить запрос к базе данных, используя ключевое слово ПОМЕСТИТЬ, после которого указать имя создаваемой временной таблицы. Ключевое слово ПОМЕСТИТЬ располагается после списка выборки запроса. Например:

ВЫБРАТЬ
Код,
Наименование
ПОМЕСТИТЬ ВременнаяТаблица
ИЗ Справочник.Номенклатура

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

В случае если менеджер временных таблиц не установлен, или менеджер был закрыт, будет выдана ошибка.

В случае если в установленном менеджере временных таблиц уже существует таблица с указанным именем, будет выдана ошибка.

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

Например:

ВЫБРАТЬ
Код,
Наименование
ПОМЕСТИТЬ ВременнаяТаблица
ИЗ Справочник.Номенклатура
ИНДЕКСИРОВАТЬ ПО Код

Поля, по которым происходит индексирование должны находиться в списке выборки.

Для того, чтобы создать временную таблицу и заблокировать данные таблиц, на основании которых создается временная, следует использовать конструкцию ДЛЯ ИЗМЕНЕНИЯ, следует использовать конструкцию ДЛЯ ИЗМЕНЕНИЯ.

Например:

ВЫБРАТЬ
РасходнаяНакладная.Ссылка,
РасходнаяНакладная.Номер,
РасходнаяНакладная.Дата
ПОМЕСТИТЬ ВременнаяТаблица
ИЗ
Документ.РасходнаяНакладная КАК РасходнаяНакладная
ГДЕ
РасходнаяНакладная.Ссылка В(&Документы)

ДЛЯ ИЗМЕНЕНИЯ

Для того чтобы создать временную таблицу на основании внешнего источника, следует в тексте запроса в списке источников указать имя параметра, в который будет помещен внешний источник. Остальной синтаксис идентичен обычному созданию временной таблицы. В качестве внешнего источника могут выступать:

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

ВЫБРАТЬ
Код,
Наименование
ПОМЕСТИТЬ ВременнаяТаблица
ИЗ &ВнешнийИсточник КАК ВнешнийИсточник

В данном примере во временную таблицу "ВременнаяТаблица" будет помещено содержимое колонок "Код" и "Наименование" из внешнего источника, например, таблицы значений, переданной в качестве параметра "ВнешнийИсточник".

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

Использование временных таблиц
Для использования существующих временных таблиц в запросе следует установить объекту Запрос менеджер временных таблиц, после чего к временным таблицам, содержащимся в данном менеджере временных таблиц, можно обращаться по имени, как к обычным таблицам запроса.

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

УНИЧТОЖИТЬ ВременнаяТаблица

В случае если уничтожаемой таблицы не существует, будет выдана ошибка.

Рассмотрим несколько ситуаций.

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

Создадим с помощью конструктора вот такой простейший запрос:

Соответственно текст запроса будет выглядеть следующим образом:

Но мы хотим поместить результат запроса во временную таблицу, которую назовем ВТ_Товары , то есть привести наш запрос вот к такому виду

Для этого нам необходимо перейти на закладку Дополнительно , установить тип запроса в положение Создание временной таблицы и заполнить поле с именем таблицы

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

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

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

Чтобы выбрать данные из временной таблицы, необходимо на закладке Таблицы и поля нажать на кнопку Создать описание временной таблицы и в открывшейся форме заполнить наименование таблицы и ее поля:

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

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

В этом случае нам надо сначала создать описание временной таблицы. А затем прописать ее имя на закладке Дополнительно .

То есть получается комбинация двух предудущих методов. Причем знак амперсанта можно также проставить в поле с именем таблицы:

Участников наших курсов часто интересует внутренняя логика работы временных таблиц.

Какие критерии индексирования временных таблиц? Где они хранятся? Нужно ли в явном виде их удалять?

Ответы на эти вопросы мы рассмотрим в данной статье.

Также мы приведем случаи, когда не нужно использовать временные таблицы .

Где хранятся временные таблицы?

Временные таблицы - это объекты СУБД, никаких временных таблиц на сервере 1С нет, и не путайте их с таблицами значений.

Под вопросом: «Где хранятся временные таблицы?» – имеется ввиду физическое расположение, т.е. либо жесткий диск, либо оперативная память.

Вероятно, этот вопрос чаще других остается без ответа, либо ответы на него кардинально различаются.

Но все сходятся в том, что временные таблицы создаются и хранятся в базе TempDB.

Действительно, все временные таблицы относятся к базе данных TempDB , но это вовсе не значит, что они обязательно будут записываться на диск.

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

Конечно, есть исключения. Например, если таблица слишком большая, то сервер может принять решение сбросить ее на диск. Также возможна ситуация, когда сервер по каким-либо причинам решил отдать память под другие данные, тогда таблица тоже будет записана на диск.

Почему таблица создается именно в памяти? Тут все очевидно – дело в производительности, думаю, не стоит объяснять, что чтение из оперативной памяти гораздо быстрее чтения с диска, даже если этот диск SSD.

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

Пишем следующий запрос в консоли:

ВЫБРАТЬ 1 КАК Поле1 ПОМЕСТИТЬ ВТ

Запускаем трассировку SQL Profiler с событием SQL:BatchComplited, выполняем запрос в консоли и получаем следующий текст SQL запроса:

INSERT INTO #tt1 (_Q_001_F_000) SELECT 1.0

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

Чтобы понять, где создается временная таблица, необходимо понять, откуда читаются данные – с диска или из памяти. Для этого используем показатель physical reads (количество физических чтений), т.е. сколько 8Кб страниц данных было прочитано с диска для выполнения запроса.

Чтобы получить значение этого показателя, необходимо выполнить создание и чтение временной таблицы в Management Studio .

Создаем новый запрос и пишем следующее:

Create table #tt1 (_Q_001_F_000 int); -- создаем локальную временную таблицу tt1 INSERT INTO #tt1 (_Q_001_F_000) SELECT 1.0 – заполняем таблицу set statistics io on; -- включаем вывод статистики ввода/вывода select * from #tt1 -- читаем данные из таблицы set statistics io off; -- выключаем вывод статистики drop table #tt1 -- удаляем таблицу

После выполнения данного кода на закладке «Сообщения» получим следующий текст:

(строк обработано: 1) Таблица «#tt1_____________________________________________000000000066″. Число просмотров 1, логических чтений 1, физических чтений 0 , упреждающих чтений 0, lob логических чтений 0, lob физических чтений 0, lob упреждающих чтений 0.

Самое важное здесь то, что данные с диска не читались, т.к. число физических чтений равно 0, при этом есть 1 логическое чтение, т.е. данные были прочитаны только из памяти.

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

Надо ли индексировать временные таблицы?

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

Но как показывает практика, чаще всего индексы во временных таблицах не используются, либо используются, но запрос выполняется еще медленнее, чем без них. Скажу даже больше: для себя я сделал вывод, что польза от индексов на временных таблицах – скорее исключение, чем правило.

Это не значит, что индексы не нужно использовать, это значит, что необходимо анализировать каждый конкретный случай, и случаев, когда индекс не нужен, значительно больше.

Именно поэтому на курсах по оптимизации постоянно делается акцент на то, что с каждой проблемой надо разбираться отдельно, а не слепо выполнять рекомендации, не понимая, почему эти рекомендации именно такие.

Давайте рассмотрим ситуацию с индексацией на примере.

Создадим временную таблицу с одним числовым полем и значениями от 1 до 1 млн.

Это можно сделать с помощью следующего пакетного запроса:

ВЫБРАТЬ 0 КАК Цифра ПОМЕСТИТЬ ВТ_Цифры ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 1 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 2 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 3 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 4 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 5 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 6 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 7 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 8 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 9 ; ////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ 100000 * Таб6.Цифра + 10000 * Таб5.Цифра + 1000 * Таб4.Цифра + 100 * Таб3.Цифра + 10 * Таб2.Цифра + Таб1.Цифра + 1 КАК Число ПОМЕСТИТЬ ВТ_Числа ИЗ ВТ_Цифры КАК Таб1, ВТ_Цифры КАК Таб2, ВТ_Цифры КАК Таб3, ВТ_Цифры КАК Таб4, ВТ_Цифры КАК Таб5, ВТ_Цифры КАК Таб6 ; ///////////////////////////////////////////////////////////// ВЫБРАТЬ ВТ_Числа.Число ИЗ ВТ_Числа КАК ВТ_Числа ГДЕ ВТ_Числа.Число = 777

Весь запрос выполняется в среднем за 1.2 секунды.

Если посмотреть трассировку SQL Profiler , то мы увидим следующее:

На создание таблицы уходит 1.1 секунда и еще 0.1 секунда на сканирование всей таблицы, чтобы вернуть нам 1 строку.

Давайте посмотрим, что изменится, если добавить индекс в таблицу ВТ_Числа .

На моем компьютере запрос стал выполняться в среднем за 6 секунд.

Время создания таблицы увеличилось с 1 секунды до 5.3, при этом даже поиск по индексу в таблице все равно происходит медленнее, чем сканирование: 0.5 сек. против 0.1 без индекса. Единственное, в чем этот запрос выигрывает, - немного меньше логических чтений: 2057 против 2233 при сканировании.

Используйте индексирование только в том случае, если вы видите от этого явный положительный эффект.

Надо ли явно удалять временные таблицы после создания?

Ответ будет зависеть от способа создания временной таблицы.

Если Вы используете временную таблицу только в одном пакетном запросе, то ваша таблица «живет», пока выполняется этот пакетный запрос. Это значит, что менеджер временных таблиц был создан неявно.

В данном случае MS SQL создает локальную временную таблицу с одной решеткой (#), например #tt1 .

Как только пакетный запрос завершается, неявный МВТ закрывается, и автоматически последует команда «Truncate table» , которая удаляет созданную таблицу.

Если временная таблица проиндексирована, то сначала будет удален индекс и только потом таблица.

Пример можно посмотреть выше в трассировке.

В данном случае нет необходимости использовать команду «УНИЧТОЖИТЬ» , только если Вы не хотите создать в том же запросе новую таблицу с таким же именем, ну или считаете это хорошим стилем написания кода.

Здесь главное понимать, что таблица все равно будет удалена при завершении пакетного запроса.

Ситуация меняется, если Вы явно используете менеджер временных таблиц (МВТ) , т.е. создаете соответствующий объект метаданных. В этом случае MS SQL создает глобальную временную таблицу с двумя решетками (##).

Такая таблица будет удалена в любом из следующих вариантов:

  1. в запросе использована команда УНИЧТОЖИТЬ
  2. вызван метод МенеджерВременныхТаблиц.Закрыть()
  3. объект МенеджерВременныхТаблиц перестал существовать, например, завершилась работа процедуры/функции, которая породила этот объект, или пользователь закрыл программу

Если Вы используете объект МВТ, то временные таблицы рекомендуется удалять одним из первых 2 методов, как только в них отпала необходимость, иначе они будут висеть в памяти сервера СУБД, пока процедура/функция не закончит работу, что не есть хорошо. Если же у Вас процедура, в которой был создан МВТ завершается как раз выполнением запроса, тогда, конечно, МВТ можно не удалять, т.к. сработает 3 условие.

Подведем итог: если Вы не используете МВТ, то явно удалять временную таблицу не требуется, она будет удалена после завершения пакетного запроса.

Если явное объявление МВТ используется, то рекомендуется удалить таблицу вручную, например, в запросе командой «Уничтожить» , либо методом МВТ.Закрыть() .

Минусы временных таблиц

Идеальных инструментов не бывает, тем более в мире 1С.

Давайте рассмотрим, какие проблемы может принести активное использование временных таблиц.

Чрезмерное разрастание базы TempDB

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

Типичная ситуация, установили обновление, и через несколько дней TempDB раздуло до неимоверных размеров, а потом выясняется, что разработчики переписали запросы с использованием временных таблиц, причем таблицы эти внушительного размера и их много.

Для исправления ситуации необходимо выполнить следующие команды:

Dbcc shrinkfile (tempdev, ЖелаемыйРазмерФайлаДанныхМб) dbcc shrinkfile (templog, ЖелаемыйРазмерФайлаЛоговМб)

Чрезмерное упрощение запросов

Нельзя сказать, что это очень большой минус, но все же.

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

Но можно встретить и другую крайность: запрос, который вполне можно было бы написать без временных таблиц, и он бы работал быстро и оптимально, все равно пишут через временные таблицы. Просто разработчику лень думать, как это можно сделать по-другому.

Если можно написать оптимальный запрос без использования временных таблиц, то лучше обойтись без них.

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

Заключение

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

Временные таблицы - это инструмент для решения определенных задач, а не волшебная таблетка на все случаи жизни.

Бурмистров Андрей

Всем привет! А точнее тем, кто все таки иногда заглядывает в это блог 🙂

После достаточно долгого отсутствия по причине полной занятости все таки решил написать очередной пост.

Недавно узнал что некоторые не знают что в платформу 1С 8.3 есть встроенный инструмент по отладке временных таблиц. Появился он относительно недавно, в одном из релизов редакции 1С 8.3.8 — «ПолучитьДанные» () применительно к МенеджеруВременныхТаблиц .

Между тем данный инструмент значительно облегчает возможности при исследовании проблем, например при разборе типовых механизмов.

Все достаточно просто.

1. Получаем временные таблицы запроса

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

2. Получаем временную таблицу для отладки

Затем мы обращаемся к нужной нам для отладки временной таблице, добавляя Получить(<Индекс таблицы>)

3. Получаем непосредственно данные

Использование метода ПолучитьДанные() позволяет получить коллекцию РезультатЗапроса непосредственно для выбранной временной таблицы.

В случае отладки непосредственно таблицы с индексом 0 (как известно, индексы и нумерация в 1С начинается с нуля) получение данных выполняется с помощью вычисления следующей строки:

Запрос.МенеджерВременныхТаблиц.Таблицы.Получить(0).ПолучитьДанные().Выгрузить()

Отладка таким образом займет меньше времени, чем используя разные «костыли» 😀

На этом все, хороших Вам разработок и с прошедшими праздниками!

PS. А для тех кто занимается поддержкой расчета зарплаты на предприятии (не только программисты), напоминаю что по этой тематике выделен отдельный ресурс Pro-Zup.info.

Если у Вас возникают по этой теме вопросы, Вы заинтересованы в расширении возможностей типовой программы или есть пожелания по устранению проблем — добро пожаловать на ресурс https://pro-zup.info/

43
NULL – отсутствующие значения. Не путать с нулевым значением! NULL – это не число, не равно пробелу, пустой ссылке, Неопределено. NULL – типообразующее значение, т.е. есть тип NULL и единственное значение этого типа. NULL... 26
Для формирования и выполнения запросов к таблицам базы данных в платформе 1С используется специальный объект языка программирования Запрос. Создается этот объект вызовом конструкции Новый Запрос. Запрос удобно... 18
В статье приведены полезные приемы при работе с запросами 1С v.8.2, а также сведения, которые не так хорошо известны о языке запросов. Я не стремлюсь дать полное описание языка запросов, а хочу остановиться лишь на... 13
ПОДОБНО - Оператор проверки строки на подобие шаблону. Аналог LIKE в SQL. Оператор ПОДОБНО позволяет сравнить значение выражения, указанного слева от него, со строкой шаблона, указанной справа. Значение выражения...




Close