Как уменьшить количество записей в регистре сведений «Версии объектов» и устранить ошибку «Недостаточно памяти»?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе активной работы пользователей и выполнения регламентных процедур в конфигурациях 1С регистр сведений ВерсииОбъектов может разрастаться до сотен тысяч и даже миллионов записей. Это приводит к сильному замедлению работы, зависанию процедуры «Тестирование и исправление», а также к ошибке «Недостаточно памяти» при попытке прочитать или очистить данные стандартными методами.

Разберем причины возникновения этой ошибки, выясним технические особенности хранения версий объектов и рассмотрим эффективные варианты очистки регистра как для файловых, так и для клиент-серверных информационных баз.

Почему возникает ошибка «Недостаточно памяти»?

Проанализируем механику работы регистра ВерсииОбъектов. В данном регистре хранятся не только метаданные версий (автор, дата, номер), но и реквизит ВерсияОбъекта, имеющий тип ХранилищеЗначения. В нем содержатся двоичные данные (сжатый XML или бинарный образ объекта).

Когда мы пытаемся выполнить запрос со всеми полями или вызвать метод набора записей Прочитать() для всей таблицы, платформа пытается одновременно загрузить в оперативную память огромный массив бинарных данных. В 32-разрядном рабочем процессе или клиенте 1С доступный объем адресного пространства ограничен 2–3 ГБ, что мгновенно приводит к аварийному завершению операции. В файловых базах ситуация усугубляется внутренними ограничениями формата 1Cv8.1CD на размер таблиц и блоков двоичных данных.

Способ 1. Порционное удаление записей через менеджер записи

Рассмотрим вариант, к которому пришел автор темы. Главная идея заключается в том, чтобы не выбирать бинарные данные и не пытаться обработать весь объем за одну итерацию. Мы выбираем только ключевые поля (или даты) небольшими порциями, после чего удаляем конкретные записи.

Разберем по шагам рабочий пример циклической обработки:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 30000
    |	ВерсииОбъектов.ДатаВерсии КАК ДатаВерсии
    |ИЗ
    |	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
    |ГДЕ
    |	ВерсииОбъектов.ДатаВерсии < &ДатаВерсии
    |УПОРЯДОЧИТЬ ПО
    |	ДатаВерсии";

Запрос.УстановитьПараметр("ДатаВерсии", ДатаОчистки);
Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл
    ОтборРС = Новый Структура("ДатаВерсии");
    ОтборРС.ДатаВерсии = Выборка.ДатаВерсии;
    
    ВыборкаРС = РегистрыСведений.ВерсииОбъектов.Выбрать(ОтборРС);
    Пока ВыборкаРС.Следующий() Цикл
        Менеджер = ВыборкаРС.ПолучитьМенеджерЗаписи();
        Менеджер.Удалить();
    КонецЦикла;
КонецЦикла;

Обратим внимание: в тексте запроса мы исключили реквизиты типа ХранилищеЗначения, благодаря чему оперативная память не перегружается.

Способ 2. Оптимальное удаление через пустые наборы записей и транзакции

Использование менеджера записи для каждой строки порождает большое количество дисковых операций. Наиболее производительным программным способом в 1С является выборка ключевых измерений (Объект) и запись пустого набора записей с установленным отбором.

Посмотрим на пример пакетной обработки с явным управлением транзакциями:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 1000
    |	Версии.Объект КАК Объект,
    |	Версии.НомерВерсии КАК НомерВерсии
    |ИЗ
    |	РегистрСведений.ВерсииОбъектов КАК Версии
    |ГДЕ
    |	Версии.ДатаВерсии < &ГраницаОчистки";

Запрос.УстановитьПараметр("ГраницаОчистки", ГраницаОчистки);

ЕстьДанные = Истина;
Пока ЕстьДанные Цикл
    Результат = Запрос.Выполнить();
    Если Результат.Пустой() Тогда
        Прервать;
    КонецЕсли;
    
    Выборка = Результат.Выбрать();
    
    НачатьТранзакцию();
    Пока Выборка.Следующий() Цикл
        Набор = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
        Набор.Отбор.Объект.Установить(Выборка.Объект);
        Набор.Отбор.НомерВерсии.Установить(Выборка.НомерВерсии);
        // Записываем пустой набор без вызова Прочитать()
        Набор.Записать();
    КонецЦикла;
    ЗафиксироватьТранзакцию();
КонецЦикла;

В этом сценарии метод Прочитать() не вызывается вовсе, а запись пустого набора сразу удаляет соответствующую строку из базы данных.

Способ 3. Прямая очистка средствами СУБД (для клиент-серверного режима)

Если информационная база работает под управлением Microsoft SQL Server или PostgreSQL, очистку можно выполнить на уровне СУБД в период регламентных работ. Перед выполнением обязательно создадим резервную копию базы.

Рассмотрим два подхода:

  1. Удаление порциями через DELETE:

    Выполняем удаление устаревших записей по условию даты. В таблицах 1С даты часто хранятся со смещением 2000 лет:

    
    DELETE FROM [dbo].[_InfoRgXXXX] 
    WHERE [_FldYYYY] < '40230101';
    
  2. Перенос нужных данных через TRUNCATE:

    Если записей слишком много, операция DELETE может переполнить журнал транзакций. В таком случае создают временную таблицу, копируют в нее актуальные версии, очищают основную таблицу командой TRUNCATE TABLE и возвращают сохраненные данные обратно.

Способ 4. Настройка штатных механизмов БСП

Если конфигурация разработана на базе Библиотеки стандартных подсистем (БСП), ручное написание обработок требуется не всегда. Рекомендуется настроить типовые инструменты:

  1. Перейдем в раздел Администрирование → Общие настройки → История изменений (или Версионирование объектов).
  2. Настроим правила хранения: установим срок хранения версий (например, «За последний месяц») или ограничим количество хранимых версий для часто перезаписываемых объектов.
  3. Включим и настроим расписание регламентного задания Очистка устаревших версий объектов, чтобы удаление выполнялось автоматически в фоновом режиме небольшими порциями.

Действия после удаления записей

Важно помнить: физическое удаление строк из базы 1С не уменьшает размер файла информационной базы 1Cv8.1CD на диске автоматически, так как освободившиеся страницы помечаются для повторного использования. Чтобы уменьшить размер файла и вернуть производительность «Тестированию и исправлению», выполним следующие шаги:

  1. Выгрузим информационную базу в файл выгрузки (.dt) через конфигуратор.
  2. Загрузим .dt в новую чистую информационную базу.
  3. Для файловых баз при возникновении ошибок структуры предварительно запустим утилиту chdbfl.exe из папки bin платформы 1С.
← На главную