Почему Выгрузить() возвращает пустую таблицу значений в отладчике 1С 8.3

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

Каждый разработчик 1С рано или поздно сталкивается с мистической ситуацией: запрос гарантированно возвращает данные, метод Результат.Пустой() возвращает значение Ложь, выборка в цикле успешно обходится, но при попытке выгрузить результат в таблицу значений с помощью метода Выгрузить() отладчик показывает абсолютно пустой объект — без единой строки и даже без колонок. В этой статье мы подробно разберем, почему возникает этот эффект, как работает современный механизм отладки в платформе 1С 8.3, а также детально сравним производительность и потребление памяти при использовании методов Выбрать() и Выгрузить().

Симптомы проблемы и демонстрационный код

Рассмотрим классическую ситуацию, с которой столкнулся автор темы. Нам необходимо получить остатки товаров на складах. Мы пишем простой и понятный код:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    |	ОстаткиТоваровКомпанииОстатки.Номенклатура,
    |	ОстаткиТоваровКомпанииОстатки.СкладКомпании,
    |	ОстаткиТоваровКомпанииОстатки.КоличествоОстаток
    |ИЗ
    |	РегистрНакопления.ОстаткиТоваровКомпании.Остатки(, ) КАК ОстаткиТоваровКомпанииОстатки";

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

Если Результат.Пустой() Тогда
    Сообщить("Нет товаров на учете!");
    Возврат;
Иначе
    ТЗ = Результат.Выгрузить();
КонецЕсли;

Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
    // Проверяем наличие данных во время обхода выборки
    А = Выборка[0]; 
КонецЦикла;

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

Причина: Асинхронная модель отладки в 1С 8.3

Выясним причину такого странного поведения платформы. Начиная с версии 8.3, фирма «1С» перевела механизм отладки на протокол HTTP (вместо старого TCP/IP) и внедрила концепцию асинхронного получения тяжелых данных.

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

В современных версиях платформы 1С 8.3 эта проблема решена следующим образом:

  1. Когда вы останавливаетесь на точке останова и запрашиваете просмотр переменной типа ТаблицаЗначений, отладчик мгновенно отображает ее пустую «оболочку».
  2. Параллельно в фоновом режиме отправляется запрос на сервер для сериализации и постепенной передачи строк таблицы.
  3. Пока данные загружаются по сети (особенно если вы работаете через VPN или с медленной базой данных), таблица в окне просмотра выглядит пустой. Ей требуется время на отрисовку.

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

Как быстро проверить наличие данных в ТЗ во время отладки

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

Выбрать() против Выгрузить(): Мифы и реальность работы с памятью

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

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

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

  1. Выбрать() возвращает объект ВыборкаИзРезультатаЗапроса. Это легковесная объектная обертка над уже находящимися в памяти сервера данными. Она не дублирует строки и тратит минимум ресурсов.
  2. Выгрузить() создает полноценный тяжелый объект типа ТаблицаЗначений. Платформа вынуждена заново скопировать все данные из внутреннего представления результата запроса в структуру таблицы значений, создать колонки, типы данных и системные индексы.

Проанализируем результаты замеров производительности на реальном примере (10 000 строк, в каждой строке длинное текстовое поле объемом около 245 Кб):

Как мы видим, потребление памяти отличается незначительно (всего на несколько мегабайт служебных данных ТЗ), однако время выполнения операции при выгрузке увеличивается почти на 45%. На огромных объемах данных выгрузка в ТЗ создает ощутимую дополнительную нагрузку на процессор сервера приложений.

Когда использовать Выборку, а когда — Таблицу значений?

Рассмотрим лучшие практики применения обоих подходов:

Используйте метод Выбрать(), если:

Используйте метод Выгрузить(), если:

Оптимизация алгоритмов фильтрации данных

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

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

← На главную