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

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

При обработке высоких нагрузок и больших объемов интеграционных данных разработчики 1С часто сталкиваются с ограничениями текстовых форматов XML/JSON и системными лимитами СУБД. Например, стандартное представление ЗначениеВСтрокуВнутр() или сериализация XDTO формируют избыточный по объему текст, а длина составного ключа отбора из множества измерений может превышать допустимый лимит строкового индекса SQL (442 символа для кодировки Unicode).

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

Причина проблемы: ограничение индексов и избыточность текстовых данных

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

  1. Объем и скорость парсинга: Текстовые XML/JSON данные требуют много ресурсов процессора для разбора парсером и занимают много места до сжатия в ZIP.
  2. Ограничение на длину индексируемых полей: Если ключ записи регистра сведений или отбор формируется из 10 и более измерений через ЗначениеВСтрокуВнутр(), итоговая строка легко превышает 900 символов, что делает невозможно эффективное индексирование в СУБД.

Решение 1: Хеширование составных ключей отбора (SHA-256)

Для создания быстрого индексируемого поля целесообразно использовать суррогатный ключ на основе хеш-суммы. Хеш-функция SHA-256 генерирует фиксированный размер данных (32 байта), что идеально подходит для индексирования.

Выясним причину эффективности этого подхода: вместо хранения тяжелой строки в индексируемом поле хранится компактный хеш, а полный состав ключа сохраняется в отдельном неограниченном поле или объекте. Поиск выполняется по точечному совпадению хеша.

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


Функция ПолучитьХэш(МассивОбъектов, Знач Метод = "ХешФункция.SHA256", Знач БинарныйФормат = Истина) Экспорт
    Перем ДД, ДДСтрокой;
    Ф = ?(ТипЗнч(Метод) = Тип("Строка"), ПредопределенноеЗначение(Метод), Метод);
    
    Если Не ТипЗнч(МассивОбъектов) = Тип("Массив") Тогда
        ЛокМассив = Новый Массив;
        ЛокМассив.Добавить(МассивОбъектов);
    Иначе
        ЛокМассив = МассивОбъектов;
    КонецЕсли;
    
    ПростыеТипы = Новый ОписаниеТипов("Строка,Число,Булево,Дата");
    Хеширование = Новый ХешированиеДанных(Ф);
    
    Для Каждого Эл Из ЛокМассив Цикл
        Если ПростыеТипы.СодержитТип(ТипЗнч(Эл)) Тогда
            ТекстовыйИД = XMLСтрока(Эл);
        Иначе
            ТекстовыйИД = ЗначениеВСтрокуВнутр(Эл);
        КонецЕсли;
        
        Хеширование.Добавить(ТекстовыйИД);
    КонецЦикла;
    
    Если Ф = ХешФункция.CRC32 Тогда
        Буф = Новый БуферДвоичныхДанных(8);
        Буф.ЗаписатьЦелое64(0, Хеширование.ХешСумма);
        ДД = ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(Буф);
    Иначе
        ДД = Хеширование.ХешСумма;
    КонецЕсли;
    
    Если Не БинарныйФормат Тогда
        ДДСтрокой = ПолучитьHexСтрокуИзДвоичныхДанных(ДД);
    КонецЕсли;
    
    Возврат ?(БинарныйФормат, ДД, ДДСтрокой);
КонецФункции

Использование хеширования позволяет свёртывать многомерные состояния в единый числовой или бинарный идентификатор. Это ускоряет группировку и сопоставление сложных структур данных в разы.

Решение 2: Компактная бинарная сериализация через FastInfoSet

Если требуется передавать или хранить структуру объектов в максимально сжатом виде без лишнего текстового оверхеда, рассмотрим встроенный механизм ЗаписьFastInfoset. Это бинарное представление XML-документа, поддерживаемое платформой нативно.

Посмотрим на пример сериализации произвольного объекта 1С в двоичные данные формата FastInfoSet:


Функция СериализоватьОбъектВFastInfoSet(Объект) Экспорт
    ЗаписьXML = Новый ЗаписьFastInfoset;
    ЗаписьXML.УстановитьДвоичныеДанные();
    ЗаписьXML.ЗаписатьОбъявлениеXML();
    
    ЗаписатьXML(ЗаписьXML, Объект, НазначениеТипаXML.Явное);
    
    Возврат ЗаписьXML.Закрыть();
КонецФункции

При использовании ЗаписьFastInfoset данные сжимаются непосредственно в момент записи. Полученные ДвоичныеДанные можно сразу сохранить в реквизит с типом ХранилищеЗначения или передать по сетевому каналу.

Решение 3: Сериализация через ХранилищеЗначения со сжатием

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

Разберем по шагам данный алгоритм:


// 1. Упаковываем объект в хранилище с максимальной степенью сжатия (уровень 9)
МоеХранилище = Новый ХранилищеЗначения(ИсходнаяСтруктура, Новый СжатиеДанных(9));

// 2. Сериализуем ХранилищеЗначения в XML-строку через СериализаторXDTO
ЗаписьXML = Новый ЗаписьXML();
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, МоеХранилище);
СтрокаРезультат = ЗаписьXML.Закрыть();

Этот метод эффективно сжимает повторяющиеся структуры в памяти, избавляя от необходимости создавать временные ZIP-файлы на диске.

Сравнительный анализ способов оптимизации

Проанализируем результаты применения описанных методов:

  1. Хеширование (SHA-256 / CRC32): Идеально подходит для полей поиска и индексов. Позволяет сжать составной ключ любой длины до фиксированного размера, снимая ограничения СУБД.
  2. FastInfoSet: Нативный бинарный формат, обеспечивающий минимальный размер зашифрованных данных при сериализации объектовой модели XML.
  3. Потоковый парсинг (ЧтениеXML / ЧтениеJSON): При загрузке критически больших объемов файлов (десятки гигабайт) следует отказаться от DOM-модели и СериализаторXDTO.ПрочитатьXML() в пользу последовательного чтения через ЧтениеXML.Прочитать(), что сводит потребление ОЗУ к минимуму.
← На главную