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

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с платформой 1С:Предприятие разработчики часто сталкиваются с ситуацией, когда выполнение, казалось бы, обычного запроса приводит к резкому сокращению свободного места на системном диске С. Особенно остро эта проблема проявляется при передаче в запрос ТаблицыЗначений в качестве параметра. Рассмотрим подробнее, почему это происходит, как механизмы 1С взаимодействуют с СУБД и что нужно сделать, чтобы память не «съедалась».

Разберем механизм работы временных таблиц

Прежде всего, нам необходимо понять, что происходит «под капотом» системы, когда мы используем метод УстановитьПараметр для передачи таблицы значений. В этот момент платформа не просто читает данные из памяти, она инициирует создание физической временной таблицы в хранилище СУБД.

Если мы работаем в клиент-серверном варианте, данные выгружаются в системную базу tempdb (для MS SQL Server) или в аналогичные структуры других СУБД (например, PostgreSQL). В файловом же режиме создаются временные файлы формата v8_..._tmp в каталоге временных файлов пользователя (%TEMP%). Поскольку этот каталог по умолчанию находится на диске C, мы наблюдаем его стремительное заполнение.

Выясним главную причину: Декартово произведение

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


|ИЗ
|    ВТ1 КАК ВТ1,
|    ВТ2 КАК ВТ2

В этом месте кроется критическая ошибка. Перечисление таблиц через запятую в секции ИЗ без указания условия связи в секции ГДЕ или использования оператора СОЕДИНЕНИЕ порождает так называемое декартово произведение (Cross Join).

Давайте представим: если в первой таблице ВТ1 содержится 10 000 строк, и во второй таблице ВТ2 также 10 000 строк, то результатом такого «объединения» станет таблица объемом 100 000 000 записей. Каждая строка первой таблицы будет умножена на каждую строку второй. СУБД пытается подготовить этот гигантский объем данных, записывая его во временные файлы, что мгновенно забивает диск С.

Почему место на диске не возвращается сразу?

Часто программисты замечают, что даже после закрытия сеанса 1С место на диске остается занятым. Разберем, почему это происходит:

  1. Особенности SQL Server: Файл базы данных tempdb умеет автоматически расширяться, но не умеет автоматически сжиматься. Если запрос «раздул» tempdb до 50 Гб, этот файл останется такого размера до перезагрузки службы SQL или ручного выполнения команды сжатия (Shrink).
  2. Зависшие временные файлы: В файловом режиме при аварийном завершении работы 1С файлы в папке %TEMP% могут просто не удалиться платформой.
  3. Менеджер временных таблиц: Если в коде используется объект МенеджерВременныхТаблиц и он не был явно закрыт, временные таблицы продолжат существовать в базе данных до тех пор, пока объект не будет уничтожен сборщиком мусора.

Как оптимизировать запрос и работу с памятью

Чтобы избежать подобных проблем, рассмотрим по шагам правильный подход к разработке:

1. Исправление логики объединения. Если ваша задача — просто объединить результаты двух таблиц (добавить строки одной к другой), используйте оператор ОБЪЕДИНИТЬ ВСЕ вместо перечисления таблиц в секции ИЗ. Если же нужно связать данные, всегда указывайте условие связи:


ВЫБРАТЬ
    ВТ1.Контрагент,
    ВТ2.Сумма
ИЗ
    ВТ1 КАК ВТ1
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ2 КАК ВТ2
    ПО ВТ1.Договор = ВТ2.Договор

2. Явное типизирование колонок ТЗ. Проанализируем важность типов данных. Перед передачей ТаблицыЗначений в запрос, убедитесь, что у каждой колонки жестко задан тип. Если тип колонки не определен или является строкой неограниченной длины, 1С создаст в СУБД максимально «тяжелые» поля (например, nvarchar(max)), что значительно увеличит размер временных таблиц.

3. Использование индексов. Если временная таблица большая и вы планируете соединять её с другими таблицами, обязательно создавайте индекс. Это не уменьшит объем на диске, но колоссально ускорит выполнение запроса и снизит нагрузку на дисковую подсистему.

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


Запрос.Текст = 
"ВЫБРАТЬ ... ПОМЕСТИТЬ ВТ_Данные ИЗ &ТЗ КАК ТЗ;
|/////////////////////////////////////////////////
|ВЫБРАТЬ * ИЗ ВТ_Данные;
|/////////////////////////////////////////////////
|УНИЧТОЖИТЬ ВТ_Данные";

Что делать, если диск уже переполнен?

Если проблема уже случилась и работа системы парализована, выполним следующие действия:

Соблюдение этих несложных правил позволит вам создавать производительные решения, которые не будут приводить к сбоям в работе инфраструктуры из-за нехватки свободного места.

← На главную