Работа с временными таблицами в 1С:Предприятие — одна из ключевых задач для разработчиков, которые хотят оптимизировать запросы и ускорить обработку данных. Часто возникает необходимость загрузить данные из временной таблицы напрямую в запрос, чтобы избежать лишних обращений к базе или упростить логику кода. Однако не все знают, как это сделать корректно, особенно если речь идет о больших объемах данных или специфических сценариях.
В этой статье мы разберем 5 проверенных способов загрузки временных таблиц в запросы 1С, включая нюансы работы с разными версиями платформы (1С:Предприятие 8.3 и 1С:Предприятие 8.2). Вы узнаете, как избежать типичных ошибок, какие методы наиболее эффективны для разных задач, и получите готовые примеры кода для immediate-внедрения в свои проекты. Особое внимание уделим производительности — ведь неправильная работа с временными таблицами может замедлить систему в десятки раз.
Что такое временная таблица в 1С и зачем её загружать в запрос
Временная таблица в 1С:Предприятие — это объект, который существует только в течение сеанса работы и позволяет хранить промежуточные данные для дальнейшей обработки. Она создается в оперативной памяти или на сервере (в зависимости от конфигурации) и автоматически удаляется после завершения сеанса. Основное преимущество временных таблиц — уменьшение нагрузки на базу данных, так как они позволяют избежать повторных обращений к диску.
Загрузка временной таблицы в запрос нужна в следующих случаях:
- 🔹 Оптимизация сложных отчетов. Когда нужно объединить данные из нескольких источников, но делать это напрямую в SQL-запросе неэффективно.
- 🔹 Промежуточные расчеты. Например, когда вы рассчитываете какие-то показатели (средние значения, отклонения) и потом используете их в основном запросе.
- 🔹 Работа с большими массивами данных. Если вы обрабатываете тысячи строк, временная таблица поможет избежать таймаутов.
- 🔹 Динамические фильтры. Когда условия отбора формируются программно и их нельзя жестко прописать в запросе.
Важно понимать, что временные таблицы не являются заменой постоянным таблицам базы данных. Они предназначены для временного хранения и не подходят для долговременного использования. Кроме того, их содержимое не сохраняется между сеансами работы 1С, что нужно учитывать при проектировании логики.
Способ 1: Использование конструктора запросов и параметра &ВременныеТаблицы
Самый простой и визуально понятный способ — загрузка через конструктор запросов с использованием параметра &ВременныеТаблицы. Этот метод подходит для начинающих разработчиков, так как не требует глубоких знаний синтаксиса 1С:Предприятие.
Алгоритм действий:
- Создайте временную таблицу с нужной структурой (например, через
Новый ТаблицаЗначений). - Заполните её данными.
- В конструкторе запросов добавьте параметр
&ВременныеТаблицыи укажите вашу таблицу. - В тексте запроса обратитесь к временной таблице как к обычной таблице базы данных.
Пример кода:
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Код");
ТЗ.Колонки.Добавить("Наименование");
ТЗ.Добавить().Заполнить("1", "Товар 1");
ТЗ.Добавить().Заполнить("2", "Товар 2");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыВременные.Код КАК Код,
| ТоварыВременные.Наименование КАК Наименование
|ИЗ
| &ВременныеТаблицы КАК ТоварыВременные";
Запрос.УстановитьПараметр("ВременныеТаблицы", ТЗ);
Результат = Запрос.Выполнить();
Этот метод удобен тем, что не требует ручного формирования временных таблиц в SQL-синтаксисе. Однако у него есть ограничение: не все версии 1С поддерживают такой подход (например, в 1С:Предприятие 7.7 это невозможно). Также стоит помнить, что при большом объеме данных производительность может падать.
Если временная таблица содержит более 10 000 строк, разбейте её на части и обрабатывайте пакетами. Это поможет избежать перегрузки памяти.
Способ 2: Прямое обращение к временной таблице через МенеджерВременныхТаблиц
Более гибкий и производительный способ — использование объекта МенеджерВременныхТаблиц. Этот метод позволяет явно управлять временными таблицами, создавать их с нужной структурой и загружать данные напрямую в запрос.
Преимущества метода:
- 🔹 Контроль над структурой таблицы. Вы можете явно указать типы данных колонок.
- 🔹 Высокая производительность. Данные загружаются оптимальным образом, без лишних преобразований.
- 🔹 Поддержка транзакций. Временные таблицы можно создавать в рамках транзакции и откатывать при необходимости.
Пример использования:
МенеджерВТ = Новый МенеджерВременныхТаблиц;
// Создаем временную таблицу с явным указанием структуры
Таблица = МенеджерВТ.СоздатьТаблицу("МояВременнаяТаблица");
Таблица.Колонки.Добавить("Код", Новый ОписаниеТипов("Число"));
Таблица.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка", 100));
// Заполняем данными
Строка = Таблица.Добавить();
Строка.Код = 1;
Строка.Наименование = "Товар 1";
// Используем в запросе
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос.Текст =
"ВЫБРАТЬ
| МояВременнаяТаблица.Код КАК Код,
| МояВременнаяТаблица.Наименование КАК Наименование
|ИЗ
| МояВременнаяТаблица КАК МояВременнаяТаблица";
Результат = Запрос.Выполнить();
Обратите внимание, что при использовании МенеджерВременныхТаблиц временные таблицы автоматически удаляются после выполнения запроса, если не указано иное. Это помогает избежать утечек памяти, но требует внимательного отношения к жизненному циклу объектов.
Что будет, если не очистить МенеджерВременныхТаблиц?
Если не освободить ресурсы (например, не вызвать МенеджерВТ.Очистить()), временные таблицы могут оставаться в памяти до конца сеанса, что приведет к увеличению потребления ОЗУ и возможным ошибкам при длительной работе.
Способ 3: Загрузка данных через параметр &Таблица в запросе
Еще один эффективный метод — передача таблицы значений непосредственно в запрос через параметр &Таблица. Этот подход удобен, когда вам нужно быстро загрузить данные без предварительного создания временной таблицы на сервере.
Особенности метода:
- 🔹 Простота использования. Не требуется работать с
МенеджерВременныхТаблиц. - 🔹 Ограниченная функциональность. Не все операции с временными таблицами доступны (например, нельзя создать индексы).
- 🔹 Подходит для небольших объемов данных. При больших таблицах возможны проблемы с производительностью.
Пример кода:
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("КодТовара");
ТЗ.Колонки.Добавить("Количество");
ТЗ.Добавить().Заполнить(1, 10);
ТЗ.Добавить().Заполнить(2, 20);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Наименование КАК Наименование,
| Товары.Артикул КАК Артикул,
| &Таблица.Количество КАК Количество
|ИЗ
| Справочник.Товары КАК Товары
| ЛЕВОЕ СОЕДИНЕНИЕ &Таблица КАК ТоварыКоличество
| ПО Товары.Ссылка = ТоварыКоличество.КодТовара";
Запрос.УстановитьПараметр("Таблица", ТЗ);
Результат = Запрос.Выполнить();
Этот метод часто используется для динамического формирования условий отбора. Например, когда список товаров для запроса формируется программно на основе пользовательского ввода. Однако помните, что ТаблицаЗначений в параметре запроса не оптимизирована для больших данных — при объеме более 1000 строк лучше использовать МенеджерВременныхТаблиц.
☑️ Подготовка к использованию временных таблиц
Способ 4: Использование временных таблиц в пакетных запросах
Если вам нужно выполнить несколько связанных запросов, где результат одного является входными данными для другого, удобно использовать временные таблицы в рамках пакетного запроса. Это позволяет избежать многократной передачи данных между клиентом и сервером.
Преимущества пакетных запросов:
- 🔹 Минимизация сетевого трафика. Все операции выполняются на сервере.
- 🔹 Повышение производительности. Нет необходимости передавать промежуточные результаты на клиент.
- 🔹 Поддержка транзакций. Можно откатить все изменения, если что-то пойдет не так.
Пример пакетного запроса с временной таблицей:
МенеджерВТ = Новый МенеджерВременныхТаблиц;
ТаблицаЗаказов = МенеджерВТ.СоздатьТаблицу("ЗаказыДляАнализа");
// Заполняем временную таблицу (например, заказы за последний месяц)
Запрос1 = Новый Запрос;
Запрос1.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос1.Текст =
"ВЫБРАТЬ
| ЗаказыПокупателей.Ссылка КАК Ссылка,
| ЗаказыПокупателей.Дата КАК Дата,
| ЗаказыПокупателей.СуммаДокумента КАК Сумма
|ПОМЕСТИТЬ ЗаказыДляАнализа
|ИЗ
| Документ.ЗаказПокупателя КАК ЗаказыПокупателей
|ГДЕ
| ЗаказыПокупателей.Дата МЕЖДУ &НачалоПериода И &КонецПериода";
Запрос1.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДата()));
Запрос1.УстановитьПараметр("КонецПериода", КонецМесяца(ТекущаяДата()));
Запрос1.Выполнить();
// Теперь используем временную таблицу в другом запросе
Запрос2 = Новый Запрос;
Запрос2.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос2.Текст =
"ВЫБРАТЬ
| ЗаказыДляАнализа.Дата КАК Дата,
| СУММА(ЗаказыДляАнализа.Сумма) КАК ИтогоСумма
|ИЗ
| ЗаказыДляАнализа КАК ЗаказыДляАнализа
|СГРУППИРОВАТЬ ПО
| ЗаказыДляАнализа.Дата";
Результат = Запрос2.Выполнить();
Этот подход особенно полезен для сложных аналитических отчетов, где нужно последовательно обработать данные. Например, сначала отобрать документы по критериям, затем рассчитать по ним какие-то показатели, а потом визуализировать результат. Временные таблицы в пакетных запросах позволяют сделать это максимально эффективно.
Пакетные запросы с временными таблицами сокращают время выполнения в 2-3 раза по сравнению с последовательным выполнением отдельных запросов.
Способ 5: Загрузка данных из XML или JSON во временную таблицу
Иногда данные для временной таблицы поступают из внешних источников — например, в формате XML или JSON. В этом случае их нужно сначала преобразовать в ТаблицуЗначений, а затем загрузить в запрос.
Алгоритм работы:
- Получите данные из внешнего источника (например, через
HTTPЗапрос). - Разберите
XML/JSONи заполнитеТаблицуЗначений. - Передайте таблицу в запрос одним из описанных выше методов.
Пример загрузки данных из JSON:
// Получаем JSON из внешнего API
HTTPЗапрос = Новый HTTPЗапрос("https://api.example.com/data");
Ответ = HTTPЗапрос.Выполнить();
ТекстJSON = Ответ.ПолучитьТекст();
// Разбираем JSON и формируем таблицу значений
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ТекстJSON);
Данные = ПрочитатьJSON(ЧтениеJSON);
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("ID");
ТЗ.Колонки.Добавить("Name");
Для Каждого Элемент Из Данные.Элементы Цикл
Строка = ТЗ.Добавить();
Строка.ID = Элемент.ID;
Строка.Name = Элемент.Name;
КонецЦикла;
// Используем таблицу в запросе
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВнешниеДанные.ID КАК ВнешнийID,
| ВнешниеДанные.Name КАК Наименование
|ИЗ
| &ВнешниеДанные КАК ВнешниеДанные";
Запрос.УстановитьПараметр("ВнешниеДанные", ТЗ);
Результат = Запрос.Выполнить();
Этот метод актуален для интеграций с внешними системами, когда данные приходят в структурированном виде и их нужно быстро обработать в 1С. Однако здесь важно учитывать формат данных — если JSON/XML имеет сложную вложенную структуру, его разбор может занять значительное время.
Для ускорения разбора больших JSON-файлов используйте потоковое чтение (ПотокЧтенияJSON), а не загрузку всего документа в память.
Типичные ошибки и как их избежать
При работе с временными таблицами в 1С разработчики часто сталкиваются с типичными ошибками, которые ведут к падению производительности или даже к краху системы. Рассмотрим наиболее распространенные из них и способы их предотвращения.
Ошибка 1: Неосвобождение ресурсов
Если вы создали временную таблицу через МенеджерВременныхТаблиц, но не очистили её после использования, она может оставаться в памяти до конца сеанса. Это приводит к утечкам памяти, особенно критично в длительных сеансах (например, в фоновом задании).
⚠️ Внимание: Всегда вызывайте МенеджерВТ.Очистить() после завершения работы с временными таблицами, если они больше не нужны.
Ошибка 2: Передача больших таблиц в параметре запроса
Если вы передаете ТаблицуЗначений с тысячами строк через параметр &Таблица, это может привести к значительному увеличению времени выполнения запроса. Временные таблицы на сервере работают намного быстрее.
Ошибка 3: Несоответствие типов данных
Если структура временной таблицы не совпадает с типами данных в запросе, вы получите ошибку выполнения. Например, если в таблице поле имеет тип Строка, а в запросе вы пытаетесь сравнить его с числовым полем.
⚠️ Внимание: Всегда проверяйте соответствие типов данных между временной таблицей и полями в запросе. Используйте ОписаниеТипов для явного указания типов.
Ошибка 4: Использование временных таблиц в транзакциях без контроля
Если вы создаете временную таблицу в рамках транзакции и не обрабатываете исключения, при откате транзакции таблица может остаться "висеть" в памяти. Это особенно актуально для серверных вызовов.
В таблице ниже собраны основные ошибки и способы их исправления:
| Ошибка | Причина | Решение |
|---|---|---|
| Запрос выполняется слишком долго | Передача большой ТаблицыЗначений в параметре |
Использовать МенеджерВременныхТаблиц |
| Ошибка типов при выполнении запроса | Несовпадение типов данных во временной таблице и запросе | Явно указывать типы при создании таблицы |
| Утечка памяти | Неосвобожденные временные таблицы | Вызывать МенеджерВТ.Очистить() |
| Некорректные результаты запроса | Ошибки в логике заполнения временной таблицы | Проверять данные перед загрузкой в запрос |
FAQ: Ответы на частые вопросы
Можно ли использовать временные таблицы в отчетах на СКД?
Да, временные таблицы можно использовать в Системе Компоновки Данных (СКД). Для этого нужно:
- Создать временную таблицу через
МенеджерВременныхТаблиц. - В настройках схемы компоновки данных указать её как источник.
- При формировании отчета передать менеджер временных таблиц в параметры выполнения.
Пример:
МенеджерВТ = Новый МенеджерВременныхТаблиц;
ТаблицаДанных = МенеджерВТ.СоздатьТаблицу("ДанныеДляОтчета");
// Заполняем таблицу...
Отчет = ПолучаемОтчет();
Отчет.КомпоновщикНастроек.Настройки.ИсточникДанных.УстановитьПараметр("МенеджерВТ", МенеджерВТ);
Отчет.СкомпоноватьРезультаты();
Как передать временную таблицу между серверными вызовами?
Временные таблицы существуют только в рамках одного серверного вызова. Чтобы передать данные между вызовами, используйте:
- 🔹 Хранилище значений (для небольших объемов данных).
- 🔹 Регистры сведений (для больших объемов, но с накладными расходами на запись/чтение).
- 🔹 Временные файлы (сериализация таблицы в
JSON/XMLи сохранение во временный файл).
Пример с сериализацией:
// Сериализация
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ТаблицаДанных);
ТекстJSON = ЗаписьJSON.Закрыть();
// Сохранение во временный файл
ИмяФайла = ПолучениеИмениВременногоФайла("json");
ТекстJSON.Записать(ИмяФайла);
// В другом вызове:
ТекстJSON = Новый ЧтениеТекста(ИмяФайла);
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ТекстJSON.Прочитать());
ТаблицаДанных = ПрочитатьJSON(ЧтениеJSON);
Какая максимальная размер временной таблицы в 1С?
Теоретически размер временной таблицы ограничивается только доступной памятью на сервере 1С:Предприятие. Однако на практике:
- 🔹 В файловом варианте работы ограничение — около
2 ГБна таблицу (зависит от настроек системы). - 🔹 В клиент-серверном варианте ограничение выше, но при превышении
100 000 строквозможны задержки. - 🔹 Для таблиц более
1 000 000 строкрекомендуется использовать постоянные таблицы базы данных.
⚠️ Внимание: При работе с большими временными таблицами следите за потреблением памяти на сервере. Используйте ДиагностикаПроизводительности.ЗамеритьПамять() для мониторинга.
Можно ли создать индекс на временной таблице в 1С?
Нет, в 1С:Предприятие нельзя явно создавать индексы на временных таблицах, как это делается в классических СУБД (например, CREATE INDEX в SQL). Однако:
- 🔹 Платформа 1С автоматически оптимизирует запросы к временным таблицам, если они небольшие.
- 🔹 Для ускорения работы с большими таблицами можно отсортировать данные перед загрузкой (например, по ключевому полю).
- 🔹 В некоторых случаях помогает разбиение таблицы на части по какому-либо критерию.
Как узнать, сколько временных таблиц создано в текущем сеансе?
Платформа 1С не предоставляет прямого метода для получения списка всех временных таблиц в сеансе. Однако вы можете:
- 🔹 Вести учет созданных таблиц в своей программе (например, в коллекции или регистре).
- 🔹 Использовать профилировщик (
ПрофилировщикЗапросов) для анализа используемых таблиц. - 🔹 В клиент-серверном варианте посмотреть журнал сервера 1С (если включена детальная запись).
Пример ведения учета:
Перем СписокВременныхТаблиц; // Коллекция для учета
Процедура СоздатьВременнуюТаблицу(ИмяТаблицы)
Если СписокВременныхТаблиц = Неопределено Тогда
СписокВременныхТаблиц = Новый Массив;
КонецЕсли;
СписокВременныхТаблиц.Добавить(ИмяТаблицы);
КонецПроцедуры