В процессе активной работы пользователей и выполнения регламентных процедур в конфигурациях 1С регистр сведений ВерсииОбъектов может разрастаться до сотен тысяч и даже миллионов записей. Это приводит к сильному замедлению работы, зависанию процедуры «Тестирование и исправление», а также к ошибке «Недостаточно памяти» при попытке прочитать или очистить данные стандартными методами.
Разберем причины возникновения этой ошибки, выясним технические особенности хранения версий объектов и рассмотрим эффективные варианты очистки регистра как для файловых, так и для клиент-серверных информационных баз.
Проанализируем механику работы регистра ВерсииОбъектов. В данном регистре хранятся не только метаданные версий (автор, дата, номер), но и реквизит ВерсияОбъекта, имеющий тип ХранилищеЗначения. В нем содержатся двоичные данные (сжатый XML или бинарный образ объекта).
Когда мы пытаемся выполнить запрос со всеми полями или вызвать метод набора записей Прочитать() для всей таблицы, платформа пытается одновременно загрузить в оперативную память огромный массив бинарных данных. В 32-разрядном рабочем процессе или клиенте 1С доступный объем адресного пространства ограничен 2–3 ГБ, что мгновенно приводит к аварийному завершению операции. В файловых базах ситуация усугубляется внутренними ограничениями формата 1Cv8.1CD на размер таблиц и блоков двоичных данных.
Рассмотрим вариант, к которому пришел автор темы. Главная идея заключается в том, чтобы не выбирать бинарные данные и не пытаться обработать весь объем за одну итерацию. Мы выбираем только ключевые поля (или даты) небольшими порциями, после чего удаляем конкретные записи.
Разберем по шагам рабочий пример циклической обработки:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 30000
| ВерсииОбъектов.ДатаВерсии КАК ДатаВерсии
|ИЗ
| РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
|ГДЕ
| ВерсииОбъектов.ДатаВерсии < &ДатаВерсии
|УПОРЯДОЧИТЬ ПО
| ДатаВерсии";
Запрос.УстановитьПараметр("ДатаВерсии", ДатаОчистки);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ОтборРС = Новый Структура("ДатаВерсии");
ОтборРС.ДатаВерсии = Выборка.ДатаВерсии;
ВыборкаРС = РегистрыСведений.ВерсииОбъектов.Выбрать(ОтборРС);
Пока ВыборкаРС.Следующий() Цикл
Менеджер = ВыборкаРС.ПолучитьМенеджерЗаписи();
Менеджер.Удалить();
КонецЦикла;
КонецЦикла;
Обратим внимание: в тексте запроса мы исключили реквизиты типа ХранилищеЗначения, благодаря чему оперативная память не перегружается.
Использование менеджера записи для каждой строки порождает большое количество дисковых операций. Наиболее производительным программным способом в 1С является выборка ключевых измерений (Объект) и запись пустого набора записей с установленным отбором.
Посмотрим на пример пакетной обработки с явным управлением транзакциями:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 1000
| Версии.Объект КАК Объект,
| Версии.НомерВерсии КАК НомерВерсии
|ИЗ
| РегистрСведений.ВерсииОбъектов КАК Версии
|ГДЕ
| Версии.ДатаВерсии < &ГраницаОчистки";
Запрос.УстановитьПараметр("ГраницаОчистки", ГраницаОчистки);
ЕстьДанные = Истина;
Пока ЕстьДанные Цикл
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
Прервать;
КонецЕсли;
Выборка = Результат.Выбрать();
НачатьТранзакцию();
Пока Выборка.Следующий() Цикл
Набор = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
Набор.Отбор.Объект.Установить(Выборка.Объект);
Набор.Отбор.НомерВерсии.Установить(Выборка.НомерВерсии);
// Записываем пустой набор без вызова Прочитать()
Набор.Записать();
КонецЦикла;
ЗафиксироватьТранзакцию();
КонецЦикла;
В этом сценарии метод Прочитать() не вызывается вовсе, а запись пустого набора сразу удаляет соответствующую строку из базы данных.
Если информационная база работает под управлением Microsoft SQL Server или PostgreSQL, очистку можно выполнить на уровне СУБД в период регламентных работ. Перед выполнением обязательно создадим резервную копию базы.
Рассмотрим два подхода:
Выполняем удаление устаревших записей по условию даты. В таблицах 1С даты часто хранятся со смещением 2000 лет:
DELETE FROM [dbo].[_InfoRgXXXX]
WHERE [_FldYYYY] < '40230101';
Если записей слишком много, операция DELETE может переполнить журнал транзакций. В таком случае создают временную таблицу, копируют в нее актуальные версии, очищают основную таблицу командой TRUNCATE TABLE и возвращают сохраненные данные обратно.
Если конфигурация разработана на базе Библиотеки стандартных подсистем (БСП), ручное написание обработок требуется не всегда. Рекомендуется настроить типовые инструменты:
Очистка устаревших версий объектов, чтобы удаление выполнялось автоматически в фоновом режиме небольшими порциями.Важно помнить: физическое удаление строк из базы 1С не уменьшает размер файла информационной базы 1Cv8.1CD на диске автоматически, так как освободившиеся страницы помечаются для повторного использования. Чтобы уменьшить размер файла и вернуть производительность «Тестированию и исправлению», выполним следующие шаги:
.dt) через конфигуратор..dt в новую чистую информационную базу.chdbfl.exe из папки bin платформы 1С.