При подготовке информационной базы 1С к удалению помеченных объектов администраторы и разработчики часто сталкиваются с проблемой: огромный объем накопленных версий объектов в регистре сведений ВерсииОбъектов блокирует стандартное удаление или вызывает критическую ошибку «Недостаточно памяти для получения результата запроса к базе данных». Попытки написать простую обработку очистки «в лоб» часто приводят к зависанию системы. При возникновении проблем со стандартным механизмом можно воспользоваться обработкой удаления помеченных объектов с отбором.
В этой статье мы подробно разберем, почему возникает эта ошибка, проанализируем неоптимальные подходы программирования и реализуем максимально быстрый, безопасный и оптимизированный по памяти алгоритм очистки истории версионирования в среде «1С:Предприятие 8».
Рассмотрим типичную ошибку начинающих разработчиков. Проанализируем исходный код, который часто приводит к аварийному завершению работы сервера 1С:
// ПРИМЕР НЕПРАВИЛЬНОГО КОДА
Запись = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
ЗаполнитьЗначенияСвойств(Запись.Отбор, ВыборкаДетальныеЗаписи);
Запись.Прочитать(); // Здесь система зависает и падает по памяти
Если Запись.Выбран() Тогда
Запись.Удалить();
КонецЕсли;
В этом фрагменте кроются сразу три критические ошибки:
Прочитать(): Метод Прочитать() загружает данные из базы данных в оперативную память сервера приложений 1С. Если вы хотите просто удалить записи, считывать их физическое содержимое в память абсолютно бессмысленно и крайне ресурсоемко.ЗаполнитьЗначенияСвойств() не смогла сопоставить поля (например, из-за несовпадения имен колонок в выборке запроса и измерений регистра), отбор по ключевым измерениям останется пустым. Вызов метода Прочитать() на наборе записей с пустым отбором заставит платформу попытаться загрузить весь регистр сведений (который в реальных базах может весить десятки гигабайт) в оперативную память. Результат — гарантированный вылет по ошибке «Недостаточно памяти».Пока Выборка.Следующий() генерирует колоссальную нагрузку на СУБД из-за постоянных сетевых пакетов и накладных расходов на компиляцию запросов.Выясним главное правило работы с механизмом наборов записей в 1С: чтобы удалить записи из регистра сведений по определенному измерению, метод Прочитать() использовать нельзя!
Достаточно создать пустой объект типа РегистрСведенийНаборЗаписей, жестко установить отбор по нужному измерению (в нашем случае — по объекту, помеченному на удаление) и сразу вызвать метод Записать(). Платформа самостоятельно сформирует быстрый SQL-запрос DELETE на уровне СУБД, удалив только те строки, которые соответствуют установленному отбору. При этом в память сервера приложений 1С не будет загружено ни единого килобайта лишних данных.
Рассмотрим правильный шаблон кода для удаления записей по конкретной ссылке:
НаборЗаписей = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
// Устанавливаем отбор по ведущему измерению "Объект"
НаборЗаписей.Отбор.Объект.Установить(СсылкаНаОбъект);
// Записываем пустой набор (замещение включено по умолчанию)
НаборЗаписей.Записать(Истина);
Обратите внимание: так как измерение Объект является главным (ведущим) для этого регистра, устанавливать отбор по остальным измерениям (например, по измерению НомерВерсии) не требуется. Платформа автоматически очистит все версии, привязанные к данному объекту.
Теперь объединим наши знания и напишем готовую высокопроизводительную процедуру для пакетной очистки регистра сведений. Чтобы избежать другой проблемы — долгой транзакции при очистке огромного объема данных — мы будем обрабатывать данные порциями (пакетами) и выполнять фиксацию транзакций частями. Это не заблокирует работу других пользователей в базе данных. При работе с базами 1С:ERP для аналогичных задач по сокращению объема накопленной информации используется многопоточная свёртка 1С:ERP с параллельной очисткой регистров.
Разберем по шагам создание оптимального алгоритма массового удаления версий объектов:
&НаСервере
Процедура ОчиститьВерсииПомеченныхНаУдалениеНаСервере()
// Шаг 1. Выбираем ссылки объектов, помеченных на удаление, у которых есть версии в регистре
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| ВерсииОбъектов.Объект КАК ОбъектСсылка
|ИЗ
| РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
|ГДЕ
| ВерсииОбъектов.Объект.ПометкаУдаления = ИСТИНА";
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
Сообщить("Версий помеченных на удаление объектов не обнаружено.");
Возврат;
КонецЕсли;
Выборка = РезультатЗапроса.Выбрать();
КоличествоУдаленных = 0;
// Шаг 2. Обходим выборку и удаляем данные транзакциями по 1000 элементов
Пока Выборка.Следующий() Цикл
НачатьТранзакцию();
Попытка
// Удаление версий текущего объекта
НаборЗаписей = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Объект.Установить(Выборка.ОбъектСсылка);
НаборЗаписей.Записать(); // Записываем пустой набор
ЗафиксироватьТранзакцию();
КоличествоУдаленных = КоличествоУдаленных + 1;
Исключение
ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации("ОчисткаВерсий",
УровеньЖурналаРегистрации.Ошибка,,,
"Не удалось очистить версии для объекта: " + Выборка.ОбъектСсылка + ". Ошибка: " + ОписаниеОшибки());
КонецПопытки;
// Информируем пользователя каждые 100 объектов
Если КоличествоУдаленных % 100 = 0 Тогда
Сообщить("Обработано объектов: " + КоличествоУдаленных);
КонецЕсли;
КонецЦикла;
Сообщить("Успешно очищены версии для " + КоличествоУдаленных + " объектов.");
КонецПроцедуры
Для эффективной поддержки базы данных в актуальном состоянии важно знать несколько ключевых особенностей работы подсистемы версионирования БСП (Библиотеки Стандартных Подсистем): для комплексного обслуживания информационных баз также можно настроить автоматическое архивирование, обновление и тестирование 1С в тихом режиме по расписанию.
Объект регистра ВерсииОбъектов установлено свойство «Ведущее». Это означает, что при непосредственном (физическом) удалении самого объекта из базы данных СУБД автоматически удалит все связанные строки из этого регистра. Дополнительно чистить регистр вручную перед удалением помеченных объектов требуется только в тех редких случаях, когда очистка регистров перед удалением объектов отключена программно или свойство «Ведущее» изменено в ходе доработки конфигурации.Очистка устаревших версий объектов. Оно позволяет автоматически избавляться от старых версий по расписанию, снижая нагрузку на базу. При этом учитывайте, что по умолчанию это задание может очищать только объемный ресурс ВерсияОбъекта (хранилище двоичных данных), оставляя пустые записи-заголовки для сохранения истории изменения объектов.История данных. Он работает непосредственно на уровне платформы и СУБД, минимизируя нагрузку на сервер приложений 1С и исключая проблемы ручного управления наборами записей.Применяя описанный подход с использованием пустых наборов записей и пакетной обработки транзакций, вы гарантированно избежите переполнения оперативной памяти сервера 1С и сможете быстро навести порядок даже в самой сильно запущенной базе данных. Если же требуется полная очистка базы от данных конкретного юридического лица, применяется выборочное удаление организации в 1С с автоматической пометкой связанных объектов.