В современных редакциях конфигураций, базирующихся на Библиотеке стандартных подсистем (БСП) версии 2.4 и выше (например, УТ 11.4, ERP 2.4, КА 2.4), разработчики и администраторы часто сталкиваются с изменением логики хранения присоединенных файлов. Если раньше файлы «размазывались» по множеству справочников, то теперь мы наблюдаем их концентрацию в единых таблицах. Рассмотрим подробнее, зачем это было сделано, как теперь устроена архитектура и почему типовые механизмы переноса файлов на диск иногда дают сбой.
Проанализируем ситуацию: в старых версиях БСП для каждого объекта-владельца (например, справочник ДоговорыКонтрагентов) создавался отдельный справочник ДоговорыКонтрагентовПрисоединенныеФайлы, где в реквизите типа ХранилищеЗначения лежали сами данные. Теперь же архитектура стала гибридной.
Разберем, из чего она состоит:
ДвоичныеДанныеФайлов (или ПрисоединенныеФайлы в промежуточных версиях): Именно здесь теперь сосредоточены все BLOB-объекты (двоичные данные), если не включено хранение в томах на диске. Запись в регистре связана с элементом справочника присоединенных файлов.Зачем это нужно? В первую очередь для оптимизации работы SQL-сервера. Когда данные файла лежат в той же таблице, что и его описание, любое обновление описания (например, изменение комментария или статуса) заставляет SQL-сервер перезаписывать всю огромную строку таблицы, включая тяжелые двоичные данные. Вынесение данных в отдельный регистр делает таблицу справочника «легкой», ускоряя чтение списка файлов и их модификацию.
Может возникнуть логичный вопрос: если данные всё равно лежат в одном регистре, зачем плодить десятки справочников типа ЗаказКлиентаПрисоединенныеФайлы? Ответ кроется в механизме RLS (ограничение доступа на уровне записей).
Выясним причину: если бы метаданные всех файлов (сканы паспортов сотрудников, секретные спецификации номенклатуры, счета) лежали в одной таблице, системе пришлось бы при каждом запросе строить сложнейшие соединения для проверки прав пользователя на объект-владелец. Разделение справочников позволяет:
Часто возникает непонимание: что именно удаляет эта регламентная операция? Проанализируем алгоритм работы подсистемы очистки. Она ищет следующие категории данных:
РеализацияТоваровУслуг) были физически удалены из базы, а запись в справочнике присоединенных файлов осталась.ДвоичныеДанныеФайлов или в томах на диске само тело файла отсутствует.Рассмотрим ситуацию, описанную многими разработчиками: в базе 12 Гб файлов, а типовая обработка «Перенос файлов в тома» видит лишь 20-30 Мб. Почему так происходит? Посмотрим на пример кода и логику работы БСП.
Проанализируем основные причины «невидимости» файлов для обработки:
ОпределяемыйТип.ПрисоединенныйФайл. Если при разработке или кастомизации новый справочник файлов не был включен в этот тип, система его просто проигнорирует.ТипХраненияФайла. Если из-за сбоя или некорректного импорта данных в карточке стоит «В томах на диске», но файла там нет (он фактически остался в базе), обработка его не тронет.РазмерВерсийВБазе() или механизмов выборки данных содержит логические ошибки при использовании ОБЪЕДИНИТЬ ВСЕ в цикле.Посмотрим на пример функции, которая может работать некорректно в некоторых релизах из-за специфики обхода метаданных:
&НаСервере
Функция РазмерВерсийВБазе()
УстановитьПривилегированныйРежим(Истина);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЕСТЬNULL(СУММА(ВерсииФайлов.Размер), 0) КАК Размер
|ИЗ
| Справочник.ВерсииФайлов КАК ВерсииФайлов
|ГДЕ
| ВерсииФайлов.ТипХраненияФайла = Значение(Перечисление.ТипыХраненияФайлов.ВИнформационнойБазе)";
Для Каждого ТипСправочника Из Метаданные.ОпределяемыеТипы.ПрисоединенныйФайл.Тип.Типы() Цикл
ПолноеИмяСправочника = Метаданные.НайтиПоТипу(ТипСправочника).ПолноеИмя();
Если ПолноеИмяСправочника <> "Справочник.Файлы" И ПолноеИмяСправочника <> "Справочник.ВерсииФайлов" Тогда
Запрос.Текст = Запрос.Текст +
"
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| ЕСТЬNULL(СУММА(ВерсииФайлов.Размер), 0) КАК Размер
|ИЗ
| " + ПолноеИмяСправочника + " КАК ВерсииФайлов
|ГДЕ
| ВерсииФайлов.ТипХраненияФайла = ЗНАЧЕНИЕ(Перечисление.ТипыХраненияФайлов.ВИнформационнойБазе)";
КонецЕсли;
КонецЦикла;
Результат = Запрос.Выполнить();
// Ошибка может быть здесь: если результат содержит много строк (по одной на справочник),
// а код выбирает только первую строку через Выборка.Следующий()
Выборка = Результат.Выбрать();
ОбщийРазмер = 0;
Пока Выборка.Следующий() Цикл
ОбщийРазмер = ОбщийРазмер + Выборка.Размер;
КонецЦикла;
Возврат ОбщийРазмер;
КонецФункции
В старых реализациях типовой обработки часто отсутствовал цикл Пока Выборка.Следующий(), и она возвращала размер только из первого справочника в списке метаданных, что и приводило к заниженным показателям объема данных для переноса.
Если вы столкнулись с тем, что типовая обработка не видит файлы, выполните следующие шаги:
rphost.ПрисоединенныйФайл и корректно суммирует их данные, а не берет только первую запись.ДвоичныеДанныеФайлов с реквизитом ТипХраненияФайла в справочниках метаданных.Таким образом, переход к единому регистру хранения двоичных данных — это осознанный шаг разработчиков 1С для повышения производительности SQL-запросов и упрощения управления версиями. Несмотря на возможные «детские болезни» типовых обработок переноса, данная архитектура является более современной и эффективной для высоконагруженных систем.