В процессе сопровождения и оптимизации баз данных 1С часто возникает задача очистки справочников от неиспользуемых элементов. Особенно актуально это становится, когда база данных разрастается, и необходимо удалить объекты, созданные до определенного периода (например, до 2019 года), которые не задействованы ни в одном документе или регистре. Основная сложность заключается в том, что стандартные справочники в 1С не содержат встроенного реквизита Дата.
В данной статье мы подробно рассмотрим, как решить эту задачу, проанализируем различные подходы — от анализа связей с документами до технических методов извлечения даты из уникального идентификатора (GUID).
Самый логичный и надежный с точки зрения бизнеса способ — это проверка использования элемента в транзакционных данных. Если элемент справочника не фигурирует ни в одном документе до или после определенной даты, вероятно, он является кандидатом на удаление.
Рассмотрим алгоритм реализации. Вместо того чтобы просто перебирать справочник, нам нужно составить запрос к метаданным. Посмотрим на пример логики:
До 01.01.2019.Проанализируем пример запроса, который находит используемые ссылки. Для оптимизации лучше использовать ЛЕВОЕ СОЕДИНЕНИЕ справочника с результатами поиска в документах. Если в результате соединения мы получаем NULL, значит, элемент не использовался.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Спр.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Спр
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК ДокТЧ
| ПО Спр.Ссылка = ДокТЧ.Номенклатура
|ГДЕ
| ДокТЧ.Ссылка.Дата < &ДатаГраницы
| И ДокТЧ.Ссылка ЕСТЬ NULL";
Запрос.УстановитьПараметр("ДатаГраницы", '20190101');
Результат = Запрос.Выполнить();
Если в справочнике нет реквизита даты, мы можем прибегнуть к техническому методу. В платформе 1С версии 8 уникальные идентификаторы (UUID) для новых объектов часто генерируются последовательно, и в них зашифрована временная метка (Timestamp).
Важное ограничение: этот метод работает корректно только для объектов, созданных непосредственно в текущей базе (не загруженных через обмен), и при условии, что платформа использует стандартный алгоритм генерации последовательных GUID.
Разберем, как преобразовать УникальныйИдентификатор в дату. Нам потребуется извлечь части строки ГУИДа и переставить их в определенном порядке. Рассмотрим функцию:
Функция ПолучитьДатуИзGUID(Ссылка) Экспорт
Идентификатор = Строка(Ссылка.УникальныйИдентификатор());
// GUID имеет формат: ХХХХХХХХ-ХХХХ-ХХХХ-ХХХХ-ХХХХХХХХХХХХ
// Временные метки содержатся в первых трех группах
Часть1 = Сред(Идентификатор, 16, 3);
Часть2 = Сред(Идентификатор, 10, 4);
Часть3 = Лев(Идентификатор, 8);
СтрокаВремени = "1" + Часть1 + Часть2 + Часть3;
// Преобразование шестнадцатеричного числа в дату
// Это схематичный пример, требующий преобразования из Hex в Decimal
// и учета смещения эпохи (в 1С это 15 октября 1582 года)
Возврат ДатаСоздания;
КонецФункции
Используя данный метод в цикле при переборе элементов справочника, мы можем легко отфильтровать те, чей «технический» возраст превышает требуемую границу. Посмотрим, как применить это в обработке:
Выборка = Справочники[ИмяСправочника].Выбрать();
Пока Выборка.Следующий() Цикл
ДатаОбъекта = ПолучитьДатуИзGUID(Выборка.Ссылка);
Если ДатаОбъекта < Дата'20190101' Тогда
// Проверяем на использование и помечаем на удаление
КонецЕсли;
КонецЦикла;
Если нам нужна максимальная точность и база не подвергалась «обрезанию» журнала регистрации, мы можем обратиться к нему. В журнале фиксируются события создания объектов.
Проанализируем ситуацию: мы можем программно выгрузить журнал регистрации в таблицу значений, отфильтровав события по типу «Добавление». Это позволит нам получить точный список ссылок и дат их появления в системе.
ВыгрузитьЖурналРегистрации."_$Data$_.New".
Фильтр = Новый Структура;
Фильтр.Вставить("ДатаНачала", '00010101');
Фильтр.Вставить("ДатаОкончания", '20181231235959');
Фильтр.Вставить("Событие", "_$Data$_.New");
ТаблицаСобытий = Новый ТаблицаЗначений;
ВыгрузитьЖурналРегистрации(ТаблицаСобытий, Фильтр, "Данные, Дата");
Этот метод гарантирует 100% точность даты, но может работать медленно на очень больших объемах данных журнала.
Если ваша конфигурация построена на базе «Библиотеки стандартных подсистем» (БСП), задача поиска неиспользуемых элементов значительно упрощается. Мы можем использовать функции общего назначения для поиска ссылок на объекты. Это позволит нам не писать сложные запросы ко всем документам вручную.
Рассмотрим использование метода НайтиСсылкиНаОбъекты. Мы сначала отбираем элементы справочника (например, по ГУИДу или другим косвенным признакам), а затем проверяем, есть ли на них ссылки в системе.
СписокСсылок = Новый Массив;
СписокСсылок.Добавить(СсылкаНаЭлемент);
ТаблицаСсылок = ОбщегоНазначения.НайтиСсылкиНаОбъекты(СписокСсылок);
Если ТаблицаСсылок.Количество() = 0 Тогда
// Объект нигде не используется, его можно безопасно удалять
КонецЕсли;
Часто элементы справочников (например, контрагенты или номенклатура) фиксируются в регистрах сведений при создании (цены, основные договоры и т.д.). Мы можем выполнить запрос к виртуальным таблицам СрезПервых или СрезПоследних с условием на период.
Выясним причину эффективности этого метода: обращение к индексированным виртуальным таблицам регистров происходит быстрее, чем полный перебор всех документов системы. Если для элемента справочника самая ранняя запись в регистрах датируется периодом после 2019 года, значит, до этого момента он не использовался или был создан позже.
При массовой работе с объектами важно помнить о производительности. Проанализируем несколько советов:
НЕ В в запросах. Если вы хотите найти объекты, которых нет в списке используемых, конструкция ГДЕ Ссылка НЕ В (&СписокИспользуемых) на больших данных будет крайне медленной. Всегда используйте ЛЕВОЕ СОЕДИНЕНИЕ и проверку на NULL.Таким образом, мы рассмотрели комплексный подход к задаче. Выбор конкретного метода зависит от технических условий вашей базы: наличия БСП, глубины журнала регистрации и алгоритма генерации ГУИДов. Сочетание этих методов позволит вам эффективно очистить справочники от устаревших данных.