База знаний Одина — Одинэсника › Форумы › ODIN — Форум по 1С Предприятию › Как оптимизировать удаление объектов в 1С без повторных вызовов поиска ссылок?
- В этой теме 1 ответ, 2 участника, последнее обновление 1 час, 40 минут назад сделано
Odin — Одинэсник.
-
АвторСообщения
-
-
28 мая 2026 в 12:06 #37486
1с 8.3 клиент-сервер обычные формы.
Требуется оптимизировать процедуру поиска и удаления помеченных на удаление объектов.
В функции МожноУдалитьСправочникСКаскадом для каждого элемента производится поиск ссылок методом НайтиПоСсылкам. Это очень долго. А эти ссылки уже есть в массиве МассивПомеченных (процедура УдалитьПомеченныеОбъекты)
// Главная процедура для регламентного задания
Процедура УдалитьПомеченныеОбъекты() ЭкспортИмяСобытияЖурнала = «РегламентноеЗадание.УдалениеОбъектов»;
Попытка
МассивПомеченных = НайтиПомеченныеНаУдаление();
Если МассивПомеченных.Количество() = 0 Тогда
Возврат;
КонецЕсли;МассивДляУдаления = Новый Массив;
Для Каждого Ссылка Из МассивПомеченных Цикл
// Проверяем, является ли объект элементом справочника
Если Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(Ссылка)) Тогда// Выполняем каскадный анализ и пометку подчиненных структур
Если МожноУдалитьСправочникСКаскадом(Ссылка, ИмяСобытияЖурнала) Тогда
МассивДляУдаления.Добавить(Ссылка);
КонецЕсли;Иначе
// Для остальных типов (документы и т.д.) оставляем стандартное поведение
МассивДляУдаления.Добавить(Ссылка);
EndIf;КонецЦикла;
// Финальное удаление объектов, прошедших проверку (с контролем оставшихся ссылок)
Если МассивДляУдаления.Количество() > 0 Тогда
МассивНеудаленных = Новый Массив;
УдалитьОбъекты(МассивДляУдаления, Истина, МассивНеудаленных);
КонецЕсли;Исключение
ЗаписьЖурналаРегистрации(ИмяСобытияЖурнала, УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
КонецПопытки;КонецПроцедуры
// Функция проверяет ссылки и каскадно помечает разрешенные зависимости
Функция МожноУдалитьСправочникСКаскадом(ГлавнаяСсылка, ИмяСобытияЖурнала)МассивДляПоиска = Новый Массив;
МассивДляПоиска.Добавить(ГлавнаяСсылка);// Находим все ссылки на данный элемент в базе
ТаблицаСсылок = НайтиПоСсылкам(МассивДляПоиска);МассивПодчиненныхДляПометки = Новый Массив;
НаборыЗаписейРегистров = Новый Массив;Для Каждого СтрокаСсылок Из ТаблицаСсылок Цикл
СсылкаНаЗависимость = СтрокаСсылок.Ссылка;
МетаданныеЗависимости = СсылкаНаЗависимость.Метаданные();// 1. Проверяем, является ли это подчиненным справочником
Если Метаданные.Справочники.Содержит(МетаданныеЗависимости) Тогда// Проверяем, является ли главная ссылка владельцем или родителем
ЭтоПодчиненный = (СсылкаНаЗависимость.Владелец = ГлавнаяСсылка);Если ЭтоПодчиненный Тогда
МассивПодчиненныхДляПометки.Добавить(СсылкаНаЗависимость);
Иначе
// Ссылка найдена в обычном реквизите другого справочника — удалять нельзя
Возврат Ложь;
КонецЕсли;// 2. Проверяем, является ли это Регистром Сведений
ИначеЕсли Метаданные.РегистрыСведений.Содержит(МетаданныеЗависимости) Тогда// Нам подходят только регистры, где объект — Измерение.
// Проверяем имя метаданного через его тип (для РС ссылка возвращает КлючЗаписи)
ИмяРегистра = МетаданныеЗависимости.Имя;
ИмяРеквизитаИлиИзмерения = СтрокаСсылок.Метаданные.Имя;// Проверяем, что ссылка находится именно в коллекции Измерения
Если МетаданныеЗависимости.Измерения.Найти(ИмяРеквизитаИлиИзмерения) = Неопределено Тогда
// Ссылка найдена в Ресурсе или Реквизите регистра — удалять нельзя
Возврат Ложь;
КонецЕсли;// Создаем объект набора записей для последующего удаления очисткой
Набор = РегистрыСведений[ИмяРегистра].СоздатьНаборЗаписей();
Набор.Отбор[ИмяРеквизитаИлиИзмерения].Установить(ГлавнаяСсылка);
НаборыЗаписейРегистров.Добавить(Набор);Иначе
// Ссылка найдена в Документе, Регистре Накопления и т.д. — удалять нельзя
Возврат Ложь;
КонецЕсли;КонецЦикла;
// Если дошли сюда — объект окружен только разрешенными зависимостями.
// Начинаем транзакцию очистки и пометки.
НачатьТранзакцию();
Попытка// Помечаем на удаление подчиненные справочники
Для Каждого ПодчиненныйОбъект Из МассивПодчиненныхДляПометки Цикл
ОбъектСпр = ПодчиненныйОбъект.ПолучитьОбъект();
Если ОбъектСпр <> Неопределено И Не ОбъектСпр.ПометкаУдаления Тогда
ОбъектСпр.УстановитьПометкуУдаления(Истина, Ложь); // Ложь — чтобы не запускать штатный каскад
КонецЕсли;
КонецЦикла;// Очищаем записи регистров сведений, где объект был измерением
Для Каждого НаборЗаписей Из НаборыЗаписейРегистров Цикл
НаборЗаписей.Записать(Истина);
КонецЦикла;ЗафиксироватьТранзакцию();
Возврат Истина;Исключение
ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации(ИмяСобытияЖурнала, УровеньЖурналаРегистрации.Предупреждение, , ,
«Ошибка каскадной пометки для » + ГлавнаяСсылка + «: » + ОписаниеОшибки());
Возврат Ложь;
КонецПопытки;КонецФункции
-
28 мая 2026 в 12:06 #37487
Чтобы оптимизировать процедуру удаления помеченных объектов и избежать повторных вызовов
НайтиПоСсылкамдля каждого элемента, нужно использовать уже имеющийся массив помеченных объектов (МассивПомеченных) как источник для поиска ссылок, а не делать отдельный поиск для каждого объекта.Основная идея — один раз построить структуру, которая позволит быстро проверять, есть ли ссылки на каждый из объектов из
МассивПомеченных, и использовать эту структуру в функцииМожноУдалитьСправочникСКаскадом.Вот конкретный план и пример реализации:
1. Собрать все ссылки на объекты из
МассивПомеченныходним вызовомНайтиПоСсылкам— это уже есть в процедуреУдалитьПомеченныеОбъекты.2. Построить индекс ссылок по объектам, на которые ссылаются — например, создать соответствие, где ключ — ссылка на объект из
МассивПомеченных, а значение — массив ссылок, которые на него ссылаются.3. Передавать этот индекс в функцию
МожноУдалитьСправочникСКаскадом, чтобы она не вызывалаНайтиПоСсылкамповторно, а брала ссылки из подготовленного индекса.4. В функции
МожноУдалитьСправочникСКаскадомиспользовать переданный индекс для проверки ссылок.—
### Пример кода с оптимизацией
1С (Код)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132// Главная процедура для регламентного заданияПроцедура УдалитьПомеченныеОбъекты() ЭкспортИмяСобытияЖурнала = "РегламентноеЗадание.УдалениеОбъектов";ПопыткаМассивПомеченных = НайтиПомеченныеНаУдаление();Если МассивПомеченных.Количество() = 0 ТогдаВозврат;КонецЕсли;// Один раз получить все ссылки на объекты из МассивПомеченныхТаблицаВсехСсылок = НайтиПоСсылкам(МассивПомеченных);// Построить индекс: ключ - объект из МассивПомеченных, значение - массив ссылок на негоИндексСсылок = Новый Соответствие;Для Каждого СтрокаСсылок Из ТаблицаВсехСсылок ЦиклЦелевойОбъект = СтрокаСсылок.Объект; // или как в вашей структуре - ссылка на объект, на который ссылаютсяЕсли НЕ ИндексСсылок.Содержит(ЦелевойОбъект) ТогдаИндексСсылок.Вставить(ЦелевойОбъект, Новый Массив);КонецЕсли;ИндексСсылок[ЦелевойОбъект].Добавить(СтрокаСсылок);КонецЦикла;МассивДляУдаления = Новый Массив;Для Каждого Ссылка Из МассивПомеченных ЦиклЕсли Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(Ссылка)) Тогда// Передаем индекс ссылок, чтобы не искать зановоЕсли МожноУдалитьСправочникСКаскадом(Ссылка, ИмяСобытияЖурнала, ИндексСсылок) ТогдаМассивДляУдаления.Добавить(Ссылка);КонецЕсли;ИначеМассивДляУдаления.Добавить(Ссылка);КонецЕсли;КонецЦикла;Если МассивДляУдаления.Количество() > 0 ТогдаМассивНеудаленных = Новый Массив;УдалитьОбъекты(МассивДляУдаления, Истина, МассивНеудаленных);КонецЕсли;ИсключениеЗаписьЖурналаРегистрации(ИмяСобытияЖурнала, УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());КонецПопытки;КонецПроцедуры// Функция проверяет ссылки и каскадно помечает разрешенные зависимости// Добавлен параметр ИндексСсылок - соответствие ссылок на объектыФункция МожноУдалитьСправочникСКаскадом(ГлавнаяСсылка, ИмяСобытияЖурнала, ИндексСсылок = Неопределено)Если ИндексСсылок = Неопределено Тогда// Если индекс не передан, делаем поиск (для обратной совместимости)МассивДляПоиска = Новый Массив;МассивДляПоиска.Добавить(ГлавнаяСсылка);ТаблицаСсылок = НайтиПоСсылкам(МассивДляПоиска);ИначеЕсли НЕ ИндексСсылок.Содержит(ГлавнаяСсылка) Тогда// Нет ссылок на этот объект - можно удалятьВозврат Истина;КонецЕсли;ТаблицаСсылок = ИндексСсылок[ГлавнаяСсылка];КонецЕсли;МассивПодчиненныхДляПометки = Новый Массив;НаборыЗаписейРегистров = Новый Массив;Для Каждого СтрокаСсылок Из ТаблицаСсылок ЦиклСсылкаНаЗависимость = СтрокаСсылок.Ссылка;МетаданныеЗависимости = СсылкаНаЗависимость.Метаданные();Если Метаданные.Справочники.Содержит(МетаданныеЗависимости) ТогдаЭтоПодчиненный = (СсылкаНаЗависимость.Владелец = ГлавнаяСсылка);Если ЭтоПодчиненный ТогдаМассивПодчиненныхДляПометки.Добавить(СсылкаНаЗависимость);ИначеВозврат Ложь;КонецЕсли;ИначеЕсли Метаданные.РегистрыСведений.Содержит(МетаданныеЗависимости) ТогдаИмяРегистра = МетаданныеЗависимости.Имя;ИмяРеквизитаИлиИзмерения = СтрокаСсылок.Метаданные.Имя;Если МетаданныеЗависимости.Измерения.Найти(ИмяРеквизитаИлиИзмерения) = Неопределено ТогдаВозврат Ложь;КонецЕсли;Набор = РегистрыСведений[ИмяРегистра].СоздатьНаборЗаписей();Набор.Отбор[ИмяРеквизитаИлиИзмерения].Установить(ГлавнаяСсылка);НаборыЗаписейРегистров.Добавить(Набор);ИначеВозврат Ложь;КонецЕсли;КонецЦикла;НачатьТранзакцию();ПопыткаДля Каждого ПодчиненныйОбъект Из МассивПодчиненныхДляПометки ЦиклОбъектСпр = ПодчиненныйОбъект.ПолучитьОбъект();Если ОбъектСпр <> Неопределено И Не ОбъектСпр.ПометкаУдаления ТогдаОбъектСпр.УстановитьПометкуУдаления(Истина, Ложь);КонецЕсли;КонецЦикла;Для Каждого НаборЗаписей Из НаборыЗаписейРегистров ЦиклНаборЗаписей.Записать(Истина);КонецЦикла;ЗафиксироватьТранзакцию();Возврат Истина;ИсключениеОтменитьТранзакцию();ЗаписьЖурналаРегистрации(ИмяСобытияЖурнала, УровеньЖурналаРегистрации.Предупреждение, , ,"Ошибка каскадной пометки для " + ГлавнаяСсылка + ": " + ОписаниеОшибки());Возврат Ложь;КонецПопытки;КонецФункции—
### Ключевые моменты:
—
НайтиПоСсылкамвызывается один раз для всего массива помеченных объектов.
— Построен индекс ссылок для быстрого доступа к ссылкам на конкретный объект.
— ФункцияМожноУдалитьСправочникСКаскадомпринимает этот индекс и не делает повторных запросов.
— Если индекс не передан, функция работает как раньше (для обратной совместимости).—
Такой подход значительно уменьшит количество вызовов поиска ссылок и ускорит процедуру удаления, особенно при большом количестве помеченных объектов.
-
-
АвторСообщения
- Для ответа в этой теме необходимо авторизоваться.