Как получить список используемых документов в 1С 8?

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

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

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

Способ 1. Поочередный опрос таблиц через цикл и «ВЫБРАТЬ ПЕРВЫЕ 1»

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

Посмотрим на пример реализации данного алгоритма:


СписокИспользуемых = Новый Массив;
Запрос = Новый Запрос;

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

Разберем логику работы этого кода:

  1. Цикл последовательно перебирает каждый объект из коллекции Метаданные.Документы.
  2. Для каждого вида документа подставляется его имя в секцию ИЗ текста запроса.
  3. Метод Результат.Пустой() позволяет мгновенно проверить, вернулись ли данные, не тратя время и оперативную память на выгрузку записей в таблицу значений.
  4. Если в таблице есть хотя бы один документ, его имя добавляется в результирующий массив.

Способ 2. Формирование единого запроса с объединением результатов

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

Рассмотрим пример формирования такого запроса:


ТекстЗапроса = "";
Запрос = Новый Запрос;

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

Запрос.Текст = ТекстЗапроса;
ТаблицаИспользуемых = Запрос.Выполнить().Выгрузить();

Для Каждого Стр Из ТаблицаИспользуемых Цикл
    Сообщить(Стр.ИмяДокумента);
КонецЦикла;

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

Способ 3. Использование объектной выборки через менеджер документа

В платформе 1С существует возможность проверки наличия данных без написания текста запроса — с помощью метода менеджера Выбрать().

Посмотрим на пример с объектным обходом:


МассивИспользуемых = Новый Массив;

Для Каждого МетаданныеДокумента Из Метаданные.Документы Цикл
    Выборка = Документы[МетаданныеДокумента.Имя].Выбрать();
    Если Выборка.Следующий() Тогда
        МассивИспользуемых.Добавить(МетаданныеДокумента.Имя);
    КонецЕсли;
КонецЦикла;

Проанализируем производительность этого метода: вызов Выбрать() без параметров неявно генерирует тяжелый запрос к базе данных, который пытается подготовить курсор для чтения всей таблицы со всеми реквизитами. Даже если мы вызываем Выборка.Следующий() всего один раз, платформа выполняет избыточную работу на стороне сервера. Запрос с конструкцией ВЫБРАТЬ ПЕРВЫЕ 1 отрабатывает в разы быстрее, особенно на базах с большим объемом данных.

Уточнение условий: проведенные документы и период

На практике пустой или тестовый документ, помеченный на удаление, не всегда означает реальное использование функционала. Чтобы отсечь ошибочные или неактуальные данные, в текст запроса следует добавить условия отбора:


Запрос.Текст = 
    "ВЫБРАТЬ ПЕРВЫЕ 1
    |	Док.Ссылка КАК Ссылка
    |ИЗ
    |	Документ." + МетаданныеДокумента.Имя + " КАК Док
    |ГДЕ
    |	НЕ Док.ПометкаУдаления
    |	И Док.Проведен
    |	И Док.Дата >= &ДатаНачала";

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

Права доступа и привилегированный режим

Если запускать обработку под учетной записью с ограниченными правами, обращение к документу, на который у пользователя нет прав чтения, вызовет системное исключение «Нарушение прав доступа» или приведет к искажению результатов из-за механизма RLS (ограничения доступа на уровне записей).

Для корректного сбора данных рекомендуется выполнять проверку в привилегированном режиме с помощью метода УстановитьПривилегированныйРежим(Истина) либо предварительно проверять наличие прав у пользователя функцией ПравоДоступа("Чтение", МетаданныеДокумента).

← На главную