Сокращение размера регистра "Версии объектов" в УПП 1.3.


Сделал хранение данных в регистре более оптимальным. Промаркировал все версии объекта с помощью хеш функции, одинаковые хеши — одинаковые версии. Почистил поле ВерсияОбъекта для всех одинаковых версий, кроме первой. Если нужно вытянуть почищенные данные, то находим первую версию объекта с таким же хешем. Использовал поля, которые уже есть в конфигурации.

Возможно о надоевшем, так как с версиями объектов как только не боролись. Нашел неплохой способ использовать реквизиты, которые в регистре были не задействованы. 

В общем, как и многие, в один прекрасный день столкнулся с тем, что регистр сведений «Версии объектов» разросся так сильно, что стал занимать очень много места на SQL. Порядка 4 миллионов записей, половина из которых — дубли. Одно из решений — обработка по удалению одинаковых версий объектов. Решение логичное, но есть одно но — с моей точки зрения, для документов использовать нельзя, так как при перепроведении документа, его движения могут кардинально измениться, из-за изменений настроек программы, учетной политики и т.п. Пройдемся обработкой — даже не узнаем о том, что кто-то что-то перепроводил и не найдем проблему. То есть для данной ситуации важна сама запись в регистре, без данных о версии объекта.
Возникла следующая идея — писать в поле регистра хеш версии объекта, если версии совпадают — хеш одинаковый. Удалять информацию о версии объекта из всех записей с одинаковым хешем, кроме первой. А хеш использовать как ключ поиска. Этим мы решим проблему дублирования и будем видеть все обращения к объектам. Придется переделать отчет истории изменения объектов, чтобы он искал нужную версию объекта по хешу, но это пустяки.
На практике — регистр уже огромный, добавление или изменение его реквизитов приведет к долгой и ненужной реструктуризации. Но оказалось что в регистре уже есть все нужные реквизиты, они просто не используются: УдалитьСжато, Комментарий, ВерсияПроигнорирована.
Решил использовать эти реквизиты для своей задачи: УдалитьСжато — флаг того что запись содержит данные версии (система ставит в истину по умолчанию), Комментарий — строка хеша версии объекта, ВерсияПроигнорирована — запись регистра обработана.

Чтобы не увеличить время записи объектов в системе, обработку регистра вынес в регламентное задание. Регламентное задание разбито на две части — первая проставляет хеши (используется CRC32 как более быстрый) для записей с пустыми хешами. Вторая — чистит версии объектов у записей с одинаковым хешем. Снимает флаг СодержитДанные если версия очищена, и ставит флаг ЗаписьОтработана в любом случае, чтобы не отрабатывать ее в дальнейшем. 

Поставил регламентное задание, оно отрабатывало наверно недели две по ночам. Но результат хороший. Делал давно, поэтома сравнивая с данными по проществии года.

Результаты. Было следующее соотношение: количество записей 3,8 млн записей — объем с индексами 14 гигабайт. Сейчас, спустя год 25,3 млн записей, объем с индексами — 31 гигабайт. То есть было примерно 3,5 гигабайта на миллион записей, сейчас — чуть более гигабайта. 

Текст процедуры регламентного задания:

Процедура УдалитьДублиВерсийОбъектов()    Экспорт
// Используемые поля регистра ВерсииОбъектов:
// Комментарий - хеш версии объекта (ключ для поиска версии)
// ВерсияПроигнорирована - используется наоборот, как флаг того что запись регистра полностью отработана - проставлен хеш, и проверена на дубли
// УдалитьСжато - признак того что запись содержит данные о версии объекта, если Ложь - то данные стерты, и нужны искать запись объекта с таким же хешем и с флагом.
// ищем не проставленные хеши объектов
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 100
|    ВерсииОбъектов.Объект
|ПОМЕСТИТЬ ОбъектыБезХеша
|ИЗ
|    РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
|ГДЕ
|    ВерсииОбъектов.Комментарий = """"
|    И ВерсииОбъектов.Объект <> НЕОПРЕДЕЛЕНО
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|    ВерсииОбъектов.Объект,
|    ВерсииОбъектов.НомерВерсии
|ИЗ
|    РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
|        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ОбъектыБезХеша КАК ОбъектыБезХеша
|        ПО ВерсииОбъектов.Объект = ОбъектыБезХеша.Объект
|ГДЕ
|    ВерсииОбъектов.Комментарий = """"";

// проставляем хеши. CRC32 - самый простой и быстрый.

Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Запись = РегистрыСведений.ВерсииОбъектов.СоздатьМенеджерЗаписи();
ЗаполнитьЗначенияСвойств(Запись, Выборка);
Запись.Прочитать();
Если Запись.Выбран() Тогда
ХешМастер = Новый ХешированиеДанных(ХешФункция.CRC32);
ХешМастер.Добавить(Запись.ВерсияОбъекта.Получить());
Запись.Комментарий = Формат(ХешМастер.ХешСумма,"ЧГ=");
КонецЕсли;
Запись.Записать();
КонецЦикла;
КонецЕсли;

// удаляем дубли версий
Запрос.Текст = "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 100
|    ВерсииОбъектов.Объект
|ПОМЕСТИТЬ НеОбработанныеОбъекты
|ИЗ
|    РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
|ГДЕ
|    ВерсииОбъектов.ВерсияПроигнорирована = ЛОЖЬ
|    И ВерсииОбъектов.Комментарий <> """"
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|    ВерсииОбъектов.Объект,
|    ВерсииОбъектов.НомерВерсии,
|    ВерсииОбъектов.Комментарий КАК Хеш
|ПОМЕСТИТЬ НеОбработанныеЗаписи
|ИЗ
|    РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
|        ВНУТРЕННЕЕ СОЕДИНЕНИЕ НеОбработанныеОбъекты КАК НеОбработанныеОбъекты
|        ПО ВерсииОбъектов.Объект = НеОбработанныеОбъекты.Объект
|ГДЕ
|    ВерсииОбъектов.ВерсияПроигнорирована = ЛОЖЬ
|    И ВерсииОбъектов.Комментарий <> """"
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|    НеОбработанныеЗаписи.Объект КАК Объект,
|    НеОбработанныеЗаписи.НомерВерсии,
|    НеОбработанныеЗаписи.Хеш,
|    МИНИМУМ(ЕСТЬNULL(ВерсииОбъектов.НомерВерсии, 0)) КАК НомерВерсииЭталон
|ИЗ
|    НеОбработанныеЗаписи КАК НеОбработанныеЗаписи
|        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
|        ПО НеОбработанныеЗаписи.Объект = ВерсииОбъектов.Объект
|            И НеОбработанныеЗаписи.Хеш = ВерсииОбъектов.Комментарий
|            И НеОбработанныеЗаписи.НомерВерсии > ВерсииОбъектов.НомерВерсии
|
|СГРУППИРОВАТЬ ПО
|    НеОбработанныеЗаписи.Объект,
|    НеОбработанныеЗаписи.НомерВерсии,
|    НеОбработанныеЗаписи.Хеш";

Результат = Запрос.Выполнить();

Если Не Результат.Пустой() Тогда

Выборка = Результат.Выбрать();

Пока Выборка.Следующий() Цикл

Запись = РегистрыСведений.ВерсииОбъектов.СоздатьМенеджерЗаписи();
ЗаполнитьЗначенияСвойств(Запись, Выборка);
Запись.Прочитать();
Если Запись.Выбран() Тогда
Если Выборка.НомерВерсииЭталон <> 0 Тогда
Запись.ВерсияОбъекта = Новый ХранилищеЗначения("");
Запись.УдалитьСжато = Ложь;
КонецЕсли;
Запись.ВерсияПроигнорирована = Истина;
КонецЕсли;
Запись.Записать();

КонецЦикла;

КонецЕсли;

КонецПроцедуры

Отчет по версиям объектов можете допилить сами, если лень, то в приложении отчет готовый, с возможностью выбора нескольких объектов и с поиском ссылок.

Может кому-то пригодиться.

10 Comments

  1. ice-net

    Почему бы просто не удалить записи с одинаковыми версиями? Зачем оставлять запись без данных?

    Reply
  2. ice-net

    и перед записью новой версии проверять изменился объект или нет.

    Reply
  3. Infector

    На уровне SQL Версии уже сжаты, но на уровне выгрузки в DT это беда-печаль. У себя решили путем переноса содержимого Регистра в базу-архив, где регистр имеет аналогичную рабочей базе конфигурацию

    Reply
  4. fxmike

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

    Reply
  5. fxmike

    (2) Если перезаписывать тысячу объектов, то мы получаем накладные расходы на тысячу сравнений с прошлыми версиями. Я не хочу падения производительности на записи. Пусть отрабатывает регламент тогда, когда это никто не видит.

    Reply
  6. fxmike

    (3) тоже хорошее решение, как обращаетесь из рабочей базы в базу архив?

    Reply
  7. fxmike

    (3) Как вариант, можно сделать отдельную базу с простой структурой регистра, в которой вместо ссылочного поля будет строка идентификатора объекта (чтобы не зависеть от структуры основной конфигурации). Вытягивать информацию можно веб-сервисом. Записывать тоже,регламентным заданием.

    Reply
  8. Infector

    (6)COM-Соединение. Сбором — переносом версий заведует регламентное задание в базе-архиве. А из основной в случае необходимости можно подключиться для просмотра в отчете/восстановления

    Reply
  9. Константин С.

    Самое первое что надо сделать: Определить актуальность данных, глубина хранения данных. В большей части прошлогодние данные уже не нужны, вот их удалять)

    Reply
  10. lrs

    Реквизиты с наименованием УдалитьЧтоТо разработчик подготавливает к физическому удалению. Надо быть готовым, что реквизит УдалитьСжато в одной из очередных редакций может исчезнуть…

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *