Тип ХранилищеЗначения в 1С 8.3: как класть в базу файлы, картинки и таблицы и не замедлить её

· 9 мин

Содержание

Хранилище значений в 1С — это тип данных ХранилищеЗначения, который позволяет записать в реквизит, константу или ресурс регистра сведений почти любое значение: файл, картинку, таблицу значений, структуру настроек. Значение упаковывается в двоичный «контейнер» и кладётся в базу целиком. Достают его методом Получить(), и работать с ним нужно на сервере.

Типичная ситуация: программисту поручают хранить скан договора прямо в карточке контрагента или фото товара в номенклатуре. Строкой это не сохранить, ссылкой на файл на диске — ненадёжно. Тут и нужна настройка реквизита с типом ХранилищеЗначения, а дальше — аккуратная работа с ним, чтобы база не разбухла и списки не начали тормозить.

Как устроено хранилище значений и для чего оно в 1С

ХранилищеЗначения — обёртка. Внутри лежит сериализованное значение, снаружи платформа видит просто двоичные данные. Отсюда главное свойство: сравнивать, сортировать, индексировать и искать по содержимому такого поля нельзя.

Что обычно кладут в хранилище:

  • 📎 файлы — ДвоичныеДанные сканов, договоров, выгрузок;
  • 🖼 картинки — фото товаров, логотипы, подписи и печати для печатных форм;
  • 📊 табличные документы — сохранённые печатные формы и отчёты;
  • 🧩 коллекции — ТаблицаЗначений, Структура, Массив, СписокЗначений с настройками или промежуточными расчётами.

Где можно создать поле такого типа:

Объект метаданныхМожно ли тип ХранилищеЗначения
Реквизит справочника, документа, плана видов характеристикДа
Реквизит табличной частиДа
КонстантаДа
Ресурс и реквизит регистра сведенийДа
Измерение регистраНет — по нему нужен отбор и индекс
Ресурс регистра накопленияНет — ресурсы там только числовые

Чем хранилище значений не является

Название путает. В 1С есть несколько похожих по имени механизмов, и под один запрос часто ищут разное:

МеханизмЧто этоГде живёт
ХранилищеЗначенияТип данных для поля в базеВ таблице объекта
Временное хранилищеПередача данных между клиентом и сервером в пределах сеансаВ памяти сервера, адрес — строка
Хранилища настроек (ХранилищеОбщихНастроек и др.)Настройки пользователей, форм, отчётовВ служебных таблицах
Хранилище конфигурацииГрупповая разработка конфигурацииОтдельный каталог или сервер хранилища

Эта страница — про первое. Временное хранилище встретится ниже: без него картинку из базы на форму не вывести.

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

Сначала поле, потом код. Порядок для нового реквизита:

  1. Откройте Конфигуратор, в дереве метаданных выберите справочник, например Номенклатура.
  2. На вкладке «Данные» добавьте реквизит, назовите его ФотоТовара.
  3. В свойстве «Тип» выберите ХранилищеЗначения.
  4. Обновите конфигурацию базы данных (F7).

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

Записывают данные всегда на сервере. Значение заворачивают в конструктор Новый ХранилищеЗначения(Значение, Сжатие):

&НаСервереБезКонтекста
Процедура СохранитьФото(СсылкаНаТовар, АдресВоВременномХранилище)

	ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресВоВременномХранилище);

	ТоварОбъект = СсылкаНаТовар.ПолучитьОбъект();
	ТоварОбъект.ФотоТовара = Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(9));
	ТоварОбъект.Записать();

	УдалитьИзВременногоХранилища(АдресВоВременномХранилище);

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

Файл с компьютера пользователя сначала попадает во временное хранилище — это делает клиентский код через асинхронные методы помещения файла (например, НачатьПомещениеФайлаНаСервер). На сервер приходит только адрес.

Присваивать реквизиту «сырые» ДвоичныеДанные без конструктора нельзя: поле принимает только значение типа ХранилищеЗначения.

Чтение хранилища значений: сервер, клиент и форма

Обратная операция — метод Получить(). Он возвращает то значение, которое когда-то упаковали:

&НаСервереБезКонтекста
Функция ФотоТовара(СсылкаНаТовар)

	Хранилище = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СсылкаНаТовар, "ФотоТовара");
	Если Хранилище = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;

	Возврат Хранилище.Получить(); // ДвоичныеДанные или Неопределено, если пусто

КонецФункции

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

Как вывести картинку на управляемую форму

Поле типа ХранилищеЗначения в данные формы не попадает: клиент его не видит. Два рабочих приёма:

  1. Навигационная ссылка на реквизит. Для записанного объекта: ПолучитьНавигационнуюСсылку(Объект.Ссылка, "ФотоТовара"). Строку кладут в реквизит формы, к которому привязано поле картинки. Платформа сама отдаст данные клиенту.
  2. Временное хранилище. На сервере берут Хранилище.Получить(), кладут результат через ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор) и выводят по адресу. Подходит для новых, ещё не записанных объектов.

💡 Второй параметр УникальныйИдентификатор формы привязывает данные ко времени жизни формы. Закрыли форму — память на сервере освободилась.

Сжатие данных и хранение версий объектов

Режимы сжатия

Второй параметр конструктора — объект СжатиеДанных с уровнем от 0 до 9. Если параметр не передать, значение сохраняется без сжатия.

Что хранитеСжимать?Почему
Таблицы значений, структуры, XML, текстДа, уровень 9Текстовая сериализация сжимается в разы
Табличные документы, отчётыДаМного повторяющейся разметки
JPEG, PNG, PDF, ZIPМожно не сжиматьУже сжаты, выигрыш мизерный, а процессор тратится

Сжатие работает при записи и при каждом чтении. Для часто читаемых больших картинок это заметная нагрузка, для архивных документов — нет.

Версии данных внутри хранилища

У самого типа нет истории: новое присваивание затирает старое значение целиком. Если нужны версии — например, все редакции договора, — держите их отдельно:

  • 🗂 регистр сведений с измерениями «Объект» и «НомерВерсии» и ресурсом типа ХранилищеЗначения;
  • 🧾 подсистема версионирования объектов в конфигурациях на БСП — она так и устроена: каждая версия объекта лежит в регистре сведений в поле-хранилище;
  • 🕒 механизм «История данных» платформы — для изменений реквизитов, но не для тяжёлых вложений.

Хранилище значений в файловой и клиент-серверной базе

Физически хранилище — двоичное поле неограниченной длины в таблице объекта.

Файловая базаКлиент-серверная (SQL)
Где лежат данныеВнутри файла 1Cv8.1CDВ столбце таблицы СУБД
Тип поляВнутренний BLOB файлаMS SQL — varbinary(max) (в старых базах image), PostgreSQL — bytea
Рост базыФайл 1Cv8.1CD растёт и сам не уменьшается после удаления данныхОсвобождённое место переиспользует СУБД, файл БД без сжатия не уменьшается
Как вернуть место«Тестирование и исправление» с флагом сжатия таблицСредства СУБД: сжатие файла БД в MS SQL, VACUUM в PostgreSQL
Резервное копированиеКопия файла 1Cv8.1CD или выгрузка .dtБэкап СУБД; каждый гигабайт вложений удлиняет его

На практике это значит: файловая база с тысячами сканов быстро доходит до нескольких гигабайт. Копирование файла по сети, выгрузка .dt и проверка базы начинают занимать десятки минут.

«Тестирование и исправление» и сжатие таблиц требуют монопольного доступа. Все пользователи должны выйти из базы, их сеансы будут завершены. Запускайте вечером или в выходной и только после резервной копии.

Обмены и хранилище

В планах обмена и при выгрузке в XML содержимое хранилища превращается в Base64. Это примерно на треть больше исходного размера. Сотня фото по 2 МБ в одном пакете — около 270 МБ сообщения обмена. Поэтому вложения часто исключают из обмена или передают отдельно.

Ошибки при работе с хранилищем значений и как их найти

Диагностика: выберите симптом

Как найти, что именно раздуло базу

  1. Размер по таблицам смотрите на уровне СУБД: Конфигуратор такого разреза не даёт.
  2. В MS SQL — отчёт «Использование диска по таблицам» в SQL Server Management Studio. В PostgreSQL — запрос к pg_total_relation_size по таблицам.
  3. Имена таблиц СУБД (_Reference25, _Fld1234) сопоставьте с объектами метаданных функцией ПолучитьСтруктуруХраненияБазыДанных() на сервере.
-- PostgreSQL: десять самых тяжёлых таблиц базы
SELECT relname, pg_size_pretty(pg_total_relation_size(relid)) AS size
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 10;

Для файловой базы точного разреза по таблицам штатно нет. Косвенный признак — размер 1Cv8.1CD растёт заметно быстрее числа документов.

Оптимизация: как хранить вложения и не тормозить базу

Главный приём практиков — не держать тяжёлое хранилище в самом объекте. Каждое открытие карточки, каждое проведение документа и каждый ПолучитьОбъект() читает объект целиком вместе со всеми его хранилищами. Фото на 3 МБ в реквизите номенклатуры будет гоняться по сети при любой записи товара.

Схема, которой пользуются типовые конфигурации:

  1. Создайте регистр сведений, например ВложенияОбъектов, непериодический.
  2. Измерение Объект — ссылка на справочник или документ.
  3. Ресурс Данные — тип ХранилищеЗначения.
  4. Читайте и пишите вложение отдельным запросом, только когда оно действительно нужно.

Так карточка товара остаётся лёгкой, а картинка подтягивается только при открытии формы с фото.

Ещё несколько правил:

  • 📏 Ограничьте размер на входе. Проверяйте ДвоичныеДанные.Размер() перед записью; фото по 10 МБ для карточки товара не нужны, уменьшайте их до разумного размера.
  • 💾 Большие архивы — в тома на диске. В конфигурациях на БСП присоединённые файлы можно хранить не в базе, а в томах на файловом сервере. Настройка находится в разделе Администрирование, в группе про присоединённые файлы.
  • 🚫 Не выбирайте поле хранилища «на всякий случай». В запросах перечисляйте только нужные поля, без *.
  • 🗜 Сжимайте то, что сжимается. Структуры и таблицы — с уровнем 9, готовые JPEG и PDF — без сжатия.
  • 🔁 Исключите вложения из обмена, если на другой стороне они не нужны.
  • 🧹 Чистите временное хранилище. После обработки вызывайте УдалитьИзВременногоХранилища, иначе крупные файлы висят в памяти сервера до конца сеанса.
Перед тем как добавить поле ХранилищеЗначения
Выполнено: 0 / 6

Частые вопросы

Можно ли искать или отбирать записи по содержимому хранилища значений?
Нет. Поле типа ХранилищеЗначения нельзя использовать в условиях, сортировке и группировке запроса. Если нужен отбор, храните признак или ключевые данные рядом, в обычном реквизите.
Какой максимальный размер у одного хранилища значений?
Жёсткий предел упирается в возможности платформы и СУБД, но на практике держите одно значение в пределах единиц мегабайт. Десятки мегабайт в одном поле делают запись и обмен заметно медленнее.
Можно ли хранить в ХранилищеЗначения объект документа или справочника?
Хранят сериализуемые значения: двоичные данные, коллекции, табличные документы, ссылки. Объект целиком туда не кладут — вместо него сохраняют ссылку или выгрузку данных в структуру.
Чем хранилище значений лучше хранения файла на сетевом диске?
Файл попадает в резервную копию базы, права доступа совпадают с правами на объект, ссылка не ломается при переезде сервера. Минус — рост базы, поэтому большие архивы выносят в тома.
Видит ли расширение конфигурации реквизиты типа ХранилищеЗначения?
Да. В расширении можно добавить собственный реквизит этого типа к заимствованному объекту и работать с ним тем же кодом.