К статье
Практический материал

Разработка и Конфигурация · 12 мин

Временная таблица в условии ГДЕ запроса 1С

Как использовать временную таблицу в условии ГДЕ запроса 1С: помещение в менеджер, соединение, В ИЕРАРХИИ, индексация, типичные ошибки и примеры кода.

Условие ГДЕ по временной таблице — один из самых частых приёмов оптимизации запросов в 1С: вместо того чтобы фильтровать огромную физическую таблицу напрямую, вы сначала отбираете небольшой список нужных значений (например, номенклатуру из табличной части документа или контрагентов из внешней обработки), помещаете его во временную таблицу, а затем используете её в условии основного запроса. Такой подход сокращает объём обрабатываемых данных и делает текст запроса читабельнее.

Типовая ситуация: у вас есть таблица значений с нужными ссылками, и требуется выбрать из регистра или справочника только те записи, которые соответствуют этим ссылкам. Без временной таблицы пришлось бы либо перечислять сотни значений в условии «В (&Список)», либо соединять запрос с данными, которых в базе нет. Временная таблица решает обе проблемы.

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

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

Временная таблица в языке запросов 1С создаётся конструкцией ПОМЕСТИТЬ ИмяТаблицы и существует только в рамках менеджера временных таблиц — объекта МенеджерВременныхТаблиц. Пока менеджер жив, любой запрос, у которого свойство МенеджерВременныхТаблиц ссылается на этот же объект, может обращаться ко всем созданным в нём таблицам.

Ключевое следствие: если вы выполнили запрос с ПОМЕСТИТЬ в одном объекте Запрос, а основной запрос с условием ГДЕ — в другом объекте без общего менеджера, платформа выдаст ошибку «Таблица не найдена». Поэтому стандартный шаблон выглядит так: создаётся менеджер, он присваивается запросу (или нескольким запросам), далее пакетным запросом выполняются и создание временной таблицы, и её использование.

Временная таблица физически хранится в памяти сервера 1С или на сервере СУБД (в клиент-серверном варианте данные передаются в СУБД). Это значит, что слишком большие временные таблицы — сотни тысяч строк без необходимости — расходуют память и канал передачи. Помещайте туда только те поля и строки, которые реально нужны для условия.

Базовый пример: таблица значений в условии ГДЕ

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

Запрос = Новый Запрос;

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

Запрос.УстановитьПараметр("ТаблицаНоменклатуры", ТаблицаНоменклатуры);

Запрос.Текст =

"ВЫБРАТЬ

| Таб.Номенклатура КАК Номенклатура

|ПОМЕСТИТЬ ВТ_Номенклатура

|ИЗ

| &ТаблицаНоменклатуры КАК Таб

|

|ИНДЕКСИРОВАТЬ ПО

| Номенклатура

|;

|

|ВЫБРАТЬ

| Остатки.Номенклатура КАК Номенклатура,

| Остатки.КоличествоОстаток КАК Остаток

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки

|ГДЕ

| Остатки.Номенклатура В

| (ВЫБРАТЬ ВТ.Номенклатура ИЗ ВТ_Номенклатура КАК ВТ)";

Результат = Запрос.Выполнить().Выгрузить();

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

Порядок подключения временной таблицы к условию ГДЕ
  1. 1
    Создайте объект МенеджерВременныхТаблиц и присвойте его запросу
  2. 2
    Передайте таблицу значений параметром и поместите её во временную таблицу через ПОМЕСТИТЬ
  3. 3
    Добавьте ИНДЕКСИРОВАТЬ ПО по полю, которое участвует в условии
  4. 4
    В основном запросе напишите ГДЕ Поле В (ВЫБРАТЬ ... ИЗ ВременнаяТаблица) или соединение
  5. 5
    Выполните запрос и проверьте, что отбор сработал: количество строк соответствует ожиданию

Два способа применить временную таблицу в условии: В или соединение

Условие через В (ВЫБРАТЬ ...) — это вложенный запрос. Оно читается естественно и хорошо подходит, когда нужен только отбор, а сами данные временной таблицы в результате не требуются. СУБД обычно преобразует такой вложенный запрос в полусоединение, и при наличии индекса оно работает быстро.

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

Практическая разница в поведении: условие В не размножает строки результата, а соединение размножит, если во временной таблице есть дубли по полю связи. Если таблица значений может содержать повторяющиеся ссылки, при соединении добавьте СГРУППИРОВАТЬ или выберите РАЗЛИЧНЫЕ во временную таблицу, иначе итоговые суммы завысятся.

В или соединение — что выбрать

ГДЕ Поле В (ВЫБРАТЬ ...)

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

ВНУТРЕННЕЕ СОЕДИНЕНИЕ

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

ЛЕВОЕ СОЕДИНЕНИЕ с проверкой ЕСТЬ NULL

Используется для обратного отбора — выбрать записи, которых нет во временной таблице. Аналог условия НЕ В.

Условие В ИЕРАРХИИ по временной таблице

Отдельный частый случай — отбор по иерархии, когда во временной таблице лежат группы справочника, а выбрать нужно все элементы внутри этих групп. Здесь условие строится как ГДЕ Товары.Номенклатура В ИЕРАРХИИ (ВЫБРАТЬ ВТ.Группа ИЗ ВТ_Группы КАК ВТ). Платформа корректно обрабатывает такой вложенный запрос с иерархией.

Учтите ограничение: тип поля вложенной выборки должен совпадать с типом проверяемого поля. Если во временной таблице ссылка на один справочник, а проверяете вы поле другого типа, получите ошибку несовместимости типов ещё на этапе компиляции запроса.

Для иерархического отбора по большому числу групп вложенный запрос с В ИЕРАРХИИ обычно эффективнее, чем предварительный разворот иерархии в плоский список элементов, особенно когда глубина иерархии велика.

Производительность: индексация, состав полей и объём данных

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

Не помещайте во временную таблицу лишние поля «про запас». Каждое поле увеличивает объём передачи данных на СУБД и память под хранение. Если для условия нужна только ссылка на номенклатуру — помещайте только её. Аналогично отбирайте строки: если исходная таблица значений содержит тысячи строк, а уникальных ссылок сотни, сначала сверните или выберите РАЗЛИЧНЫЕ.

Ещё один фактор — виртуальные таблицы. Условие по временной таблице эффективнее всего применять как параметр виртуальной таблицы (например, в параметрах Остатки или СрезПоследних) либо в условии ГДЕ максимально близко к источнику данных, чтобы отбор сработал до соединений и группировок.

Типичные ошибки и ограничения платформы

Самая частая ошибка — «Временная таблица уже существует» при повторном выполнении запроса с тем же менеджером. Если запрос выполняется в цикле или несколько раз, временную таблицу нужно уничтожать (УНИЧТОЖИТЬ ВТ_Номенклатура) либо создавать новый менеджер на каждую итерацию. Обратная ошибка — «Таблица не найдена»: запрос с условием выполнен с другим менеджером или после того, как менеджер вышел из области видимости.

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

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

Типичные ошибки при работе с временными таблицами
01
Разные менеджеры у запросов — ошибка «Таблица не найдена» в условии ГДЕ
02
Нет ИНДЕКСИРОВАТЬ ПО — полное сканирование временной таблицы и резкое падение скорости
03
Дубли ссылок при соединении — размножение строк и завышенные итоги
04
Нетипизированные колонки таблицы значений — ошибка компиляции или пустой результат
05
Повторное выполнение ПОМЕСТИТЬ без УНИЧТОЖИТЬ — ошибка «таблица уже существует»
06
Помещение лишних полей и строк — перерасход памяти и трафика на СУБД

Как проверить результат и отладить запрос

Отладка начинается с проверки содержимого самой временной таблицы. Выполните отдельный запрос ВЫБРАТЬ * ИЗ ВТ_Номенклатура с тем же менеджером и убедитесь, что в ней есть строки и корректные значения. Пустая временная таблица — первая причина «запрос ничего не вернул».

Далее сравните результат двух вариантов: условия через В и соединения. Если количество строк различается — во временной таблице есть дубли или NULL. Для клиент-серверного варианта полезен технологический журнал с событиями DBMSSQL или план запроса на стороне СУБД: по нему видно, используется ли индекс временной таблицы и не превратился ли отбор в полное сканирование.

Контрольные точки

Как проверить корректность работы условия

Содержимое временной таблицы
Норма

Строки есть, значения поля связи заполнены и типизированы

Тревожный признак

Таблица пуста или поле связи содержит NULL

Количество строк результата
Норма

Совпадает с ожидаемым числом записей по отобранным ссылкам

Тревожный признак

Строк больше из-за дублей во временной таблице или результат пуст

План запроса на СУБД
Норма

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

Тревожный признак

Полное сканирование временной таблицы или основной таблицы

Частые вопросы

Можно ли использовать временную таблицу в условии ГДЕ запроса из другого объекта Запрос?

Да, но только если обоим объектам Запрос присвоен один и тот же МенеджерВременныхТаблиц. Без общего менеджера второй запрос не увидит таблицу и завершится ошибкой «Таблица не найдена».

Что быстрее: условие В с вложенным запросом или соединение с временной таблицей?

При наличии индекса разница обычно невелика, так как оптимизатор СУБД приводит оба варианта к похожему плану. Выбирайте по задаче: В — для чистого отбора, соединение — когда нужны поля из временной таблицы. Реальную разницу покажет только замер на ваших данных.

Как отобрать записи, которых НЕТ во временной таблице?

Два рабочих способа: условие ГДЕ НЕ Поле В (ВЫБРАТЬ ...) либо ЛЕВОЕ СОЕДИНЕНИЕ с условием ГДЕ ВТ.Поле ЕСТЬ NULL. Учтите, что NULL в поле временной таблицы может нарушить работу НЕ В, поэтому вариант с соединением надёжнее.

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

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

Почему запрос с временной таблицей возвращает пустой результат, хотя данные есть?

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

Можно ли передать временную таблицу в параметр виртуальной таблицы регистра?

Да, вложенный запрос к временной таблице допустим в условии параметров виртуальной таблицы, например: Остатки(, , Номенклатура В (ВЫБРАТЬ ВТ.Номенклатура ИЗ ВТ_Номенклатура КАК ВТ)). Это один из самых производительных вариантов отбора.

Итог

Что важно запомнить

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