Тип ХранилищеЗначения в 1С 8.3: как класть в базу файлы, картинки и таблицы и не замедлить её
Содержание
Хранилище значений в 1С — это тип данных ХранилищеЗначения, который позволяет записать в реквизит, константу или ресурс регистра сведений почти любое значение: файл, картинку, таблицу значений, структуру настроек. Значение упаковывается в двоичный «контейнер» и кладётся в базу целиком. Достают его методом Получить(), и работать с ним нужно на сервере.
Типичная ситуация: программисту поручают хранить скан договора прямо в карточке контрагента или фото товара в номенклатуре. Строкой это не сохранить, ссылкой на файл на диске — ненадёжно. Тут и нужна настройка реквизита с типом ХранилищеЗначения, а дальше — аккуратная работа с ним, чтобы база не разбухла и списки не начали тормозить.
Как устроено хранилище значений и для чего оно в 1С
ХранилищеЗначения — обёртка. Внутри лежит сериализованное значение, снаружи платформа видит просто двоичные данные. Отсюда главное свойство: сравнивать, сортировать, индексировать и искать по содержимому такого поля нельзя.
Что обычно кладут в хранилище:
- 📎 файлы —
ДвоичныеДанныесканов, договоров, выгрузок; - 🖼 картинки — фото товаров, логотипы, подписи и печати для печатных форм;
- 📊 табличные документы — сохранённые печатные формы и отчёты;
- 🧩 коллекции —
ТаблицаЗначений,Структура,Массив,СписокЗначенийс настройками или промежуточными расчётами.
Где можно создать поле такого типа:
| Объект метаданных | Можно ли тип ХранилищеЗначения |
|---|---|
| Реквизит справочника, документа, плана видов характеристик | Да |
| Реквизит табличной части | Да |
| Константа | Да |
| Ресурс и реквизит регистра сведений | Да |
| Измерение регистра | Нет — по нему нужен отбор и индекс |
| Ресурс регистра накопления | Нет — ресурсы там только числовые |
Чем хранилище значений не является
Название путает. В 1С есть несколько похожих по имени механизмов, и под один запрос часто ищут разное:
| Механизм | Что это | Где живёт |
|---|---|---|
ХранилищеЗначения | Тип данных для поля в базе | В таблице объекта |
| Временное хранилище | Передача данных между клиентом и сервером в пределах сеанса | В памяти сервера, адрес — строка |
Хранилища настроек (ХранилищеОбщихНастроек и др.) | Настройки пользователей, форм, отчётов | В служебных таблицах |
| Хранилище конфигурации | Групповая разработка конфигурации | Отдельный каталог или сервер хранилища |
Эта страница — про первое. Временное хранилище встретится ниже: без него картинку из базы на форму не вывести.
Подключение: создаём реквизит и записываем в него данные
Сначала поле, потом код. Порядок для нового реквизита:
- Откройте Конфигуратор, в дереве метаданных выберите справочник, например
Номенклатура. - На вкладке «Данные» добавьте реквизит, назовите его
ФотоТовара. - В свойстве «Тип» выберите
ХранилищеЗначения. - Обновите конфигурацию базы данных (
F7).
Если правите типовую конфигурацию, добавляйте реквизит через расширение, а не снимая конфигурацию с поддержки. Так обновления релизов пройдут без ручного сравнения.
Записывают данные всегда на сервере. Значение заворачивают в конструктор Новый ХранилищеЗначения(Значение, Сжатие):
&НаСервереБезКонтекста
Процедура СохранитьФото(СсылкаНаТовар, АдресВоВременномХранилище)
ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресВоВременномХранилище);
ТоварОбъект = СсылкаНаТовар.ПолучитьОбъект();
ТоварОбъект.ФотоТовара = Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(9));
ТоварОбъект.Записать();
УдалитьИзВременногоХранилища(АдресВоВременномХранилище);
КонецПроцедуры
Файл с компьютера пользователя сначала попадает во временное хранилище — это делает клиентский код через асинхронные методы помещения файла (например, НачатьПомещениеФайлаНаСервер). На сервер приходит только адрес.
Присваивать реквизиту «сырые» ДвоичныеДанные без конструктора нельзя: поле принимает только значение типа ХранилищеЗначения.
Чтение хранилища значений: сервер, клиент и форма
Обратная операция — метод Получить(). Он возвращает то значение, которое когда-то упаковали:
&НаСервереБезКонтекста
Функция ФотоТовара(СсылкаНаТовар)
Хранилище = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СсылкаНаТовар, "ФотоТовара");
Если Хранилище = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
Возврат Хранилище.Получить(); // ДвоичныеДанные или Неопределено, если пусто
КонецФункции
Функция ОбщегоНазначения.ЗначениеРеквизитаОбъекта есть в конфигурациях на БСП. В своей конфигурации без БСП сделайте то же простым запросом по одному полю — не читайте весь объект ради картинки.
Как вывести картинку на управляемую форму
Поле типа ХранилищеЗначения в данные формы не попадает: клиент его не видит. Два рабочих приёма:
- Навигационная ссылка на реквизит. Для записанного объекта:
ПолучитьНавигационнуюСсылку(Объект.Ссылка, "ФотоТовара"). Строку кладут в реквизит формы, к которому привязано поле картинки. Платформа сама отдаст данные клиенту. - Временное хранилище. На сервере берут
Хранилище.Получить(), кладут результат черезПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор)и выводят по адресу. Подходит для новых, ещё не записанных объектов.
💡 Второй параметр УникальныйИдентификатор формы привязывает данные ко времени жизни формы. Закрыли форму — память на сервере освободилась.
Сжатие данных и хранение версий объектов
Режимы сжатия
Второй параметр конструктора — объект СжатиеДанных с уровнем от 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 МБ сообщения обмена. Поэтому вложения часто исключают из обмена или передают отдельно.
Ошибки при работе с хранилищем значений и как их найти
Как найти, что именно раздуло базу
- Размер по таблицам смотрите на уровне СУБД: Конфигуратор такого разреза не даёт.
- В MS SQL — отчёт «Использование диска по таблицам» в SQL Server Management Studio. В PostgreSQL — запрос к
pg_total_relation_sizeпо таблицам. - Имена таблиц СУБД (
_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 МБ в реквизите номенклатуры будет гоняться по сети при любой записи товара.
Схема, которой пользуются типовые конфигурации:
- Создайте регистр сведений, например
ВложенияОбъектов, непериодический. - Измерение
Объект— ссылка на справочник или документ. - Ресурс
Данные— типХранилищеЗначения. - Читайте и пишите вложение отдельным запросом, только когда оно действительно нужно.
Так карточка товара остаётся лёгкой, а картинка подтягивается только при открытии формы с фото.
Ещё несколько правил:
- 📏 Ограничьте размер на входе. Проверяйте
ДвоичныеДанные.Размер()перед записью; фото по 10 МБ для карточки товара не нужны, уменьшайте их до разумного размера. - 💾 Большие архивы — в тома на диске. В конфигурациях на БСП присоединённые файлы можно хранить не в базе, а в томах на файловом сервере. Настройка находится в разделе
Администрирование, в группе про присоединённые файлы. - 🚫 Не выбирайте поле хранилища «на всякий случай». В запросах перечисляйте только нужные поля, без
*. - 🗜 Сжимайте то, что сжимается. Структуры и таблицы — с уровнем 9, готовые JPEG и PDF — без сжатия.
- 🔁 Исключите вложения из обмена, если на другой стороне они не нужны.
- 🧹 Чистите временное хранилище. После обработки вызывайте
УдалитьИзВременногоХранилища, иначе крупные файлы висят в памяти сервера до конца сеанса.