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

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

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

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

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

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

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


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

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

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

Read Full Article