Как удалить 5 миллионов записей версий объектов в 1С и почему они продолжают записываться?

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

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

В данной статье мы подробно разберем, как безопасно и быстро очистить этот регистр, выясним причины, по которым штатные механизмы могут не справляться со своей задачей, и рассмотрим альтернативные варианты удаления данных как средствами самой платформы 1С, так и напрямую на уровне СУБД (MS SQL и PostgreSQL).

Выясним причину: почему версии продолжают записываться после отключения версионирования?

Часто администраторы отключают версионирование для тяжелых справочников (например, для справочника Справочник.Номенклатура) в настройках Библиотеки Стандартных Подсистем (БСП), но с удивлением обнаруживают, что новые записи всё равно продолжают появляться в регистре. Проанализируем ситуацию и выделим три основные причины этого поведения:

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

Разберем проблему: почему штатное регламентное задание не удаляет записи?

Многие пользователи обращают внимание на странное поведение системы: регламентное задание «Очистка устаревших версий объектов» выполняется успешно, сообщает о завершении работы, но физическое количество записей в таблице РегистрСведений.ВерсииОбъектов на уровне СУБД не уменьшается (например, так и остается висеть 5 миллионов строк). Выясним причину этой технической особенности.

Дело в том, что штатное регламентное задание БСП по умолчанию спроектировано весьма специфическим образом:

В результате такого подхода сама запись регистра (метаинформация: кто изменил объект, когда это произошло и какой номер версии был присвоен) сохраняется в базе данных для ведения сквозной истории, но тяжелая часть данных стирается. База данных физически уменьшается в объеме (после последующего сжатия/реиндексации таблиц СУБД), однако общее число строк в таблице остается неизменным. Чтобы избавиться от самих строк, требуются иные инструменты.

Влияет ли удаление версий на сами объекты базы данных?

Перед тем как приступить к радикальным мерам очистки, ответим на самый важный вопрос: не повредит ли удаление версий сами документы, справочники или регистры?

Нет, не повредит. Регистр сведений РегистрСведений.ВерсииОбъектов является полностью независимым и изолированным хранилищем. В нем лежат лишь копии документов и справочников в прошлых состояниях. Если вы удалите абсолютно все записи из этого регистра — от первой до самой последней версии — сами объекты в системе останутся в целости и сохранности в своем текущем актуальном состоянии. Вы потеряете только возможность посмотреть историю изменений этих объектов («кто и что поменял») за прошлые периоды.

Способ 1. Использование внешней обработки в режиме обычного приложения

Если у вас есть проверенная внешняя обработка для очистки версий, созданная для платформы 1С 8.2 (на обычных формах), вы можете запустить её и на платформе 1С 8.3. Однако при попытке открыть её стандартным способом через «Файл - Открыть» в управляемом приложении вы можете увидеть пустое окно.

Рассмотрим по шагам, как правильно запустить такую обработку:

  1. Запустите стартер 1С:Предприятия.
  2. Выберите нужную информационную базу и нажмите кнопку «Изменить».
  3. Нажимайте кнопку «Далее», пока не дойдете до страницы дополнительных параметров запуска.
  4. В поле «Дополнительные параметры запуска» пропишите специальный ключ: /RunModeOrdinaryApplication.
  5. Запустите базу. Она откроется в режиме толстого клиента обычного приложения. Теперь вы можете открыть вашу внешнюю обработку через меню «Файл - Открыть», и она отработает корректно.

Способ 2. Сверхбыстрая очистка напрямую в СУБД (MS SQL и PostgreSQL)

Когда речь идет о 5 миллионах записей, удаление стандартными средствами 1С (например, через выборку и запись пустого набора) может занять долгие часы, сильно нагрузить процессор сервера и переполнить файлы логов транзакций (особенно актуально для файлов LDF в MS SQL). Самый быстрый способ — очистить таблицу напрямую через SQL-запрос. Это занимает всего 1–2 секунды.

Критически важно: Перед выполнением любых прямых запросов в СУБД в обязательном порядке сделайте резервную копию (бэкап) базы данных! При администрировании нескольких систем для таких задач можно заранее настроить автоматическое архивирование баз по расписанию.

Шаг 1. Как найти имя физической таблицы регистра в СУБД

Платформа 1С генерирует имена таблиц в СУБД автоматически (например, _InfoRg11265). Чтобы узнать точное имя таблицы вашего регистра версий объектов, воспользуемся встроенной функцией платформы. Нам понадобится написать и запустить простую процедуру в консоли кода:


ТаблицаСтруктуры = ПолучитьСтруктуруХраненияБазыДанных("РегистрСведений.ВерсииОбъектов", Истина);
Для Каждого СтрокаТаблицы Из ТаблицаСтруктуры Цикл
    Сообщить("Имя таблицы в СУБД: " + СтрокаТаблицы.ИмяТаблицыХранения);
КонецЦикла;

Запустив этот код, мы получим точное имя таблицы, с которой нам предстоит работать в СУБД.

Шаг 2. Выполнение очистки в Microsoft SQL Server

Откройте SQL Server Management Studio (SSMS), создайте новый запрос к вашей базе данных и выполните команду полной очистки таблицы:

TRUNCATE TABLE dbo._InfoRgXXXX;

*(где _InfoRgXXXX — физическое имя таблицы вашего регистра, полученное на Шаге 1)*.

Команда TRUNCATE работает мгновенно, так как она не записывает удаление каждой строки в лог транзакций покопийно, а просто освобождает страницы данных.

Шаг 3. Выполнение очистки в PostgreSQL

Для баз данных, развернутых на СУБД PostgreSQL, процесс аналогичен. Откройте утилиту pgAdmin, выберите вашу базу данных, откройте Query Tool и выполните команду:

TRUNCATE TABLE public._InfoRgXXXX;

Рассмотрим подробнее важные нюансы работы этой команды в PostgreSQL:

  1. Очистка TOAST-таблиц: В PostgreSQL тяжелые данные (такие как реквизит ВерсияОбъекта, имеющий тип ХранилищеЗначения) физически хранятся вне основной таблицы — в специальных служебных таблицах TOAST. Команда TRUNCATE автоматически очищает как основную таблицу регистра, так и связанную с ней таблицу TOAST. Дисковое пространство на сервере освобождается моментально. Если бы мы использовали стандартную команду DELETE, место бы не освободилось до тех пор, пока не была бы запущена ресурсоемкая процедура полной очистки VACUUM FULL.
  2. Монопольный режим блокировки: Команда TRUNCATE требует монопольной блокировки таблицы. Это значит, что перед выполнением запроса необходимо завершить все активные сеансы пользователей в 1С и желательно остановить службу сервера 1С:Предприятия. В противном случае СУБД выдаст ошибку о невозможности блокировки таблицы или возникнет блокировка процессов.

Способ 3. Безопасное программное удаление порциями средствами 1С

Если у вас файловая база данных или у вас нет прямого доступа к консоли СУБД, удаление придется производить программным методом в самой 1С. Попытка удалить 5 миллионов записей одним транзакционным пакетом гарантированно приведет к зависанию системы и нехватке оперативной памяти.

Посмотрим на пример правильного алгоритма очистки данных порциями (пакетами). Мы будем удалять записи постепенно, фиксируя транзакции небольшими частями, что позволит базе данных работать стабильно и не перегружать память.


Процедура ОчиститьРегистрВерсийПорциями()
    
    // Определим дату, до которой хотим очистить историю версий
    ДатаОчистки = '20231231235959'; // Например, до конца 2023 года
    РазмерПорции = 5000; // Оптимальный размер пакета для одной транзакции
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ " + Формат(РазмерПорции, "ЧГ=0") + "
        |	ВерсииОбъектов.Объект КАК Объект,
        |	ВерсииОбъектов.НомерВерсии КАК НомерВерсии
        |ИЗ
        |	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
        |ГДЕ
        |	ВерсииОбъектов.ДатаВерсии <= &ДатаОчистки";
    
    Запрос.УстановитьПараметр("ДатаОчистки", ДатаОчистки);
    
    СистематическоеУдаление = Истина;
    ВсегоУдалено = 0;
    
    Пока СистематическоеУдаление Цикл
        
        РезультатЗапроса = Запрос.Выполнить();
        Если РезультатЗапроса.Пустой() Тогда
            СистематическоеУдаление = Ложь;
            Прервать;
        КонецЕсли;
        
        Выборка = РезультатЗапроса.Выбрать();
        
        НачатьТранзакцию();
        Попытка
            Пока Выборка.Следующий() Цикл
                
                // Создаем набор записей с отбором по ключевым полям для удаления конкретной записи
                НаборЗаписей = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
                НаборЗаписей.Отбор.Объект.Установить(Выборка.Объект);
                НаборЗаписей.Отбор.НомерВерсии.Установить(Выборка.НомерВерсии);
                
                // Записываем пустой набор, тем самым удаляя запись
                НаборЗаписей.Записать(Истина);
                ВсегоУдалено = ВсегоУдалено + 1;
                
            КонецЦикла;
            ЗафиксироватьТранзакцию();
        Исключение
            ОтменитьТранзакцию();
            ЗаписьЖурналаРегистрации("ОчисткаВерсий", УровеньЖурналаРегистрации.Ошибка,,, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
            ВызватьИсключение "Произошла ошибка при очистке порции данных. Процесс остановлен.";
        КонецПопытки;
        
        #Если Клиент Тогда
            Состояние("Удалено записей: " + ВсегоУдалено);
            ОбработкаПрерыванияПользователя();
        #КонецЕсли
        
    КонецЦикла;
    
    ПоказатьПредупреждение(,"Очистка завершена успешно! Всего удалено записей: " + ВсегоУдалено);
    
КонецПроцедуры

Этот код выбирает первые 5000 устаревших записей, в рамках одной транзакции удаляет их поочередно через запись пустого набора записей с установленным отбором, фиксирует транзакцию и переходит к следующей итерации цикла. Такой подход абсолютно безопасен для стабильности системы, его можно прерывать в любой момент без риска повреждения базы данных.

Используя предложенные методы, вы сможете быстро решить проблему огромного объема регистра версий объектов, оптимизировать работу СУБД и значительно уменьшить размер вашей базы данных 1С.

← На главную