При проведении аудита незнакомой базы данных, подготовке к переходу на новую конфигурацию или оптимизации учетной системы разработчику часто требуется выяснить, какие именно документы реально используются пользователями, а какие присутствуют в конфигурации только номинально. Простой просмотр дерева метаданных не дает ответа на этот вопрос, так как в типовых конфигурациях содержатся сотни видов документов, из которых на конкретном предприятии задействована лишь малая часть.
Разберем по шагам различные технические способы решения этой задачи: от динамического построения запросов на встроенном языке 1С до применения прямых запросов к СУБД и штатных инструментов платформы.
Платформа 1С:Предприятие не позволяет в тексте запроса обращаться к метаданным напрямую через служебные таблицы. Однако мы можем программно обойти коллекцию метаданных в цикле, составить единый текст запроса с объединением таблиц и выполнить его один раз. Чтобы сразу получить полезную статистику, включим в выборку количество документов и дату последней записи.
Посмотрим на пример кода обработки:
ШаблонЗапроса = "
|ВЫБРАТЬ
| ""#ИмяДокумента"" КАК ВидДокумента,
| КОЛИЧЕСТВО(1) КАК Количество,
| МАКСИМУМ(#Таблица.Дата) КАК ДатаПоследнего
|ИЗ
| #Таблица КАК #Таблица
|";
ТекстЗапроса = "";
Для Каждого МДДокумент Из Метаданные.Документы Цикл
ТекстФрагмента = СтрЗаменить(ШаблонЗапроса, "#ИмяДокумента", МДДокумент.Синоним);
ТекстФрагмента = СтрЗаменить(ТекстФрагмента, "#Таблица", "Документ." + МДДокумент.Имя);
ТекстЗапроса = ТекстЗапроса + ?(ПустаяСтрока(ТекстЗапроса), "", "
|ОБЪЕДИНИТЬ ВСЕ
|") + ТекстФрагмента;
КонецЦикла;
Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Если Выборка.Количество > 0 Тогда
Сообщить(СтрШаблон("Вид: %1 | Всего: %2 | Последний: %3",
Выборка.ВидДокумента,
Выборка.Количество,
Выборка.ДатаПоследнего));
КонецЕсли;
КонецЦикла;
Разберем важные детали этой реализации:
МАКСИМУМ(Дата) позволяет сразу отсечь документы, которые вводились много лет назад при тестовых запусках и больше не используются в реальных бизнес-процессах.ГДЕ #Таблица.Дата МЕЖДУ &Дата1 И &Дата2.Если задача заключается исключительно в том, чтобы зафиксировать сам факт наличия хотя бы одного документа каждого вида (без подсчета точного количества), объединение полных таблиц является избыточным. При объемах базы в миллионы записей агрегация займет продолжительное время.
В этом случае эффективнее проверять наличие первой попавшейся записи с помощью конструкции ВЫБРАТЬ ПЕРВЫЕ 1 и метода Пустой() объекта РезультатЗапроса:
СписокИспользуемых = Новый Массив;
УстановитьПривилегированныйРежим(Истина);
Запрос = Новый Запрос;
Для Каждого МДДокумент Из Метаданные.Документы Цикл
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1 1 ИЗ Документ." + МДДокумент.Имя;
Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
СписокИспользуемых.Добавить(МДДокумент.Имя);
КонецЕсли;
КонецЦикла;
Для Каждого ИмяДокумента Из СписокИспользуемых Цикл
Сообщить("Используется: " + ИмяДокумента);
КонецЦикла;
Обратим внимание на следующие архитектурные особенности:
УстановитьПривилегированныйРежим(Истина) отключает RLS на время проверки.ОБЪЕДИНИТЬ ВСЕ в один текст может вызвать ошибку переполнения стека парсера или превышение лимитов SQL-сервера. Пакетный опрос таблиц или выполнение легких запросов с конструкцией ПЕРВЫЕ 1 гарантирует стабильность выполнения.В клиент-серверном варианте базы данных (например, на Microsoft SQL Server) можно быстро получить список заполненных таблиц документов напрямую через системные таблицы, минуя прослойку сервера 1С.
Посмотрим на пример запроса T-SQL, который возвращает размер и наличие страниц данных для таблиц документов:
SELECT
t.name AS TableName,
MIN(t.create_date) AS CreateDate,
ds.name AS FileGroupName,
SUM(u.total_pages) * 8 / 1024 AS SizeMB
FROM sys.tables AS t
INNER JOIN sys.partitions AS p ON t.object_id = p.object_id
INNER JOIN sys.allocation_units AS u ON p.partition_id = u.container_id
INNER JOIN sys.data_spaces AS ds ON u.data_space_id = ds.data_space_id
WHERE t.name LIKE '_Document%'
GROUP BY t.name, ds.name
HAVING SUM(u.total_pages) > 0
ORDER BY SizeMB DESC;
Выясним причину формулы * 8 / 1024: в MS SQL Server страница данных занимает 8 килобайт. Умножая количество страниц (total_pages) на 8, мы получаем размер в килобайтах, а деление на 1024 переводит его в мегабайты.
Чтобы сопоставить физические имена таблиц СУБД (например, _Document120) с объектами метаданных конфигурации, во встроенном языке 1С применяется специальный метод ПолучитьСтруктуруХраненияБазыДанных(), который возвращает таблицу соответствия объектов конфигурации и таблиц базы данных.
Если нет возможности писать программный код, можно воспользоваться стандартными средствами:
Таким образом, для быстрого разового анализа достаточно динамического запроса с подсчетом КОЛИЧЕСТВО(1) и МАКСИМУМ(Дата) в привилегированном режиме, а для высоконагруженных баз оптимальным решением является поочередная проверка через ВЫБРАТЬ ПЕРВЫЕ 1 либо анализ таблиц на стороне СУБД.