При обработке высоких нагрузок и больших объемов интеграционных данных разработчики 1С часто сталкиваются с ограничениями текстовых форматов XML/JSON и системными лимитами СУБД. Например, стандартное представление ЗначениеВСтрокуВнутр() или сериализация XDTO формируют избыточный по объему текст, а длина составного ключа отбора из множества измерений может превышать допустимый лимит строкового индекса SQL (442 символа для кодировки Unicode).
В этой статье разберем по шагам, как оптимизировать сериализацию объектов, минимизировать объем передаваемых данных в оперативной памяти и обойти ограничения на длину индекса с помощью хеширования и нативных механизмов платформы.
Проанализируем ситуацию, когда необходимо хранить историю изменений или выполнять частые отборы по сложным многомерным ключам. Стандартный подход имеет два узких места:
ЗначениеВСтрокуВнутр(), итоговая строка легко превышает 900 символов, что делает невозможно эффективное индексирование в СУБД.Для создания быстрого индексируемого поля целесообразно использовать суррогатный ключ на основе хеш-суммы. Хеш-функция SHA-256 генерирует фиксированный размер данных (32 байта), что идеально подходит для индексирования.
Выясним причину эффективности этого подхода: вместо хранения тяжелой строки в индексируемом поле хранится компактный хеш, а полный состав ключа сохраняется в отдельном неограниченном поле или объекте. Поиск выполняется по точечному совпадению хеша.
Рассмотрим пример функции получения хеш-суммы для произвольного массива объектов или измерений ключа:
Функция ПолучитьХэш(МассивОбъектов, Знач Метод = "ХешФункция.SHA256", Знач БинарныйФормат = Истина) Экспорт
Перем ДД, ДДСтрокой;
Ф = ?(ТипЗнч(Метод) = Тип("Строка"), ПредопределенноеЗначение(Метод), Метод);
Если Не ТипЗнч(МассивОбъектов) = Тип("Массив") Тогда
ЛокМассив = Новый Массив;
ЛокМассив.Добавить(МассивОбъектов);
Иначе
ЛокМассив = МассивОбъектов;
КонецЕсли;
ПростыеТипы = Новый ОписаниеТипов("Строка,Число,Булево,Дата");
Хеширование = Новый ХешированиеДанных(Ф);
Для Каждого Эл Из ЛокМассив Цикл
Если ПростыеТипы.СодержитТип(ТипЗнч(Эл)) Тогда
ТекстовыйИД = XMLСтрока(Эл);
Иначе
ТекстовыйИД = ЗначениеВСтрокуВнутр(Эл);
КонецЕсли;
Хеширование.Добавить(ТекстовыйИД);
КонецЦикла;
Если Ф = ХешФункция.CRC32 Тогда
Буф = Новый БуферДвоичныхДанных(8);
Буф.ЗаписатьЦелое64(0, Хеширование.ХешСумма);
ДД = ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(Буф);
Иначе
ДД = Хеширование.ХешСумма;
КонецЕсли;
Если Не БинарныйФормат Тогда
ДДСтрокой = ПолучитьHexСтрокуИзДвоичныхДанных(ДД);
КонецЕсли;
Возврат ?(БинарныйФормат, ДД, ДДСтрокой);
КонецФункции
Использование хеширования позволяет свёртывать многомерные состояния в единый числовой или бинарный идентификатор. Это ускоряет группировку и сопоставление сложных структур данных в разы.
Если требуется передавать или хранить структуру объектов в максимально сжатом виде без лишнего текстового оверхеда, рассмотрим встроенный механизм ЗаписьFastInfoset. Это бинарное представление XML-документа, поддерживаемое платформой нативно.
Посмотрим на пример сериализации произвольного объекта 1С в двоичные данные формата FastInfoSet:
Функция СериализоватьОбъектВFastInfoSet(Объект) Экспорт
ЗаписьXML = Новый ЗаписьFastInfoset;
ЗаписьXML.УстановитьДвоичныеДанные();
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписатьXML(ЗаписьXML, Объект, НазначениеТипаXML.Явное);
Возврат ЗаписьXML.Закрыть();
КонецФункции
При использовании ЗаписьFastInfoset данные сжимаются непосредственно в момент записи. Полученные ДвоичныеДанные можно сразу сохранить в реквизит с типом ХранилищеЗначения или передать по сетевому каналу.
В случаях, когда структуры данных содержат сложные прикладные типы (таблицы значений, соответствия, структуры), удобным способом является упаковка через ХранилищеЗначения с максимальным уровнем сжатия и последующей XDTO-сериализацией.
Разберем по шагам данный алгоритм:
// 1. Упаковываем объект в хранилище с максимальной степенью сжатия (уровень 9)
МоеХранилище = Новый ХранилищеЗначения(ИсходнаяСтруктура, Новый СжатиеДанных(9));
// 2. Сериализуем ХранилищеЗначения в XML-строку через СериализаторXDTO
ЗаписьXML = Новый ЗаписьXML();
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, МоеХранилище);
СтрокаРезультат = ЗаписьXML.Закрыть();
Этот метод эффективно сжимает повторяющиеся структуры в памяти, избавляя от необходимости создавать временные ZIP-файлы на диске.
Проанализируем результаты применения описанных методов:
СериализаторXDTO.ПрочитатьXML() в пользу последовательного чтения через ЧтениеXML.Прочитать(), что сводит потребление ОЗУ к минимуму.