Как в 1С программно получить список непустых регистров сведений

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

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

Разбор распространенных ошибок при проверке данных регистра

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


Для Каждого РегистрИзМетаданных Из Метаданные.РегистрыСведений Цикл
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ КОЛИЧЕСТВО(*) ИЗ РегистрСведений." + РегистрИзМетаданных.Имя;
    Выборка = Запрос.Выполнить().Выбрать();
    
    КоличествоЗаписей = 0;
    Пока Выборка.Следующий() Цикл
        НаборЗаписей = РегистрыСведений[РегистрИзМетаданных.Имя].СоздатьНаборЗаписей();
        НаборЗаписей.Прочитать();
        КоличествоЗаписей = НаборЗаписей.Количество() + КоличествоЗаписей;
    КонецЦикла;
КонецЦикла;

В этом коде присутствуют две критические проблемы:

  1. Ошибка чтения подчиненных регистров: если регистр сведений имеет режим записи Подчинение регистратору, вызов НаборЗаписей.Прочитать() без предварительной установки отбора по регистратору вызовет исключение платформы 1С.
  2. Избыточность операций: одновременное использование запроса с КОЛИЧЕСТВО(*) и последующее чтение всех данных через СоздатьНаборЗаписей() многократно увеличивает нагрузку на сервер и память, дублируя одну и ту же работу.

Способ 1. Оптимальная проверка через запрос с конструкцией ВЫБРАТЬ ПЕРВЫЕ 1

Для определения того, пуст ли регистр, нам не требуется подсчитывать точное количество строк с помощью КОЛИЧЕСТВО(*). На больших объемах данных подсчет количества приводит к полному сканированию таблицы (Full Table Scan). Достаточно выяснить сам факт наличия хотя бы одной записи, используя конструкцию ВЫБРАТЬ ПЕРВЫЕ 1 1 и метод Пустой() объекта РезультатЗапроса.

Посмотрим на пример правильного кода с обходом метаданных:


СписокЗаполненныхРегистров = Новый Массив;

УстановитьПривилегированныйРежим(Истина);

Для Каждого МДРегистр Из Метаданные.РегистрыСведений Цикл
    ИмяРегистра = МДРегистр.Имя;
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |	1 КАК Поле
        |ИЗ
        |	РегистрСведений." + ИмяРегистра + " КАК Таблица";
        
    Результат = Запрос.Выполнить();
    
    Если Не Результат.Пустой() Тогда
        СписокЗаполненныхРегистров.Добавить(ИмяРегистра);
    КонецЕсли;
КонецЦикла;

УстановитьПривилегированныйРежим(Ложь);

Обратите внимание: мы используем УстановитьПривилегированныйРежим(Истина), чтобы ограничения на уровне записей (RLS) или недостаток прав у текущего пользователя не исказили результат выборки.

Способ 2. Формирование пакетного запроса

Выполнение запроса в цикле по каждому регистру порождает множество сетевых обращений между сервером 1С и СУБД. Если в конфигурации сотни регистров, эффективнее собрать один пакетный запрос или объединить их через ОБЪЕДИНИТЬ ВСЕ.

Разберем реализацию пакетного запроса:


СписокЗаполненныхРегистров = Новый Массив;
МассивИменРегистров = Новый Массив;
ТекстыЗапросов = Новый Массив;

УстановитьПривилегированныйРежим(Истина);

Для Каждого МДРегистр Из Метаданные.РегистрыСведений Цикл
    МассивИменРегистров.Добавить(МДРегистр.Имя);
    ТекстыЗапросов.Добавить(
        "ВЫБРАТЬ ПЕРВЫЕ 1 1 ИЗ РегистрСведений." + МДРегистр.Имя
    );
КонецЦикла;

Если ТекстыЗапросов.Количество() > 0 Тогда
    Запрос = Новый Запрос;
    Запрос.Текст = СтрСоединить(ТекстыЗапросов, ";" + Символы.ПС);
    
    ПакетРезультатов = Запрос.ВыполнитьПакет();
    
    Для Индекс = 0 По ПакетРезультатов.ВГраница() Цикл
        Если Не ПакетРезультатов[Индекс].Пустой() Тогда
            СписокЗаполненныхРегистров.Добавить(МассивИменРегистров[Индекс]);
        КонецЕсли;
    КонецЦикла;
КонецЕсли;

УстановитьПривилегированныйРежим(Ложь);

Такой подход минимизирует накладные расходы на сетевое взаимодействие с базой данных и отрабатывает существенно быстрее.

Важные нюансы при работе с данными

  1. Права доступа: если код выполняется без привилегированного режима, рекомендуется проверять доступность объекта через ПравоДоступа("Чтение", МДРегистр) во избежание ошибок авторизации.
  2. Разделение данных (SaaS): в облачных базах с включенными разделителями стандартный запрос возвратит только записи текущей области данных. Если требуется анализ всей базы, процедуру необходимо запускать в сеансе без указания разделителей.
← На главную