В процессе сопровождения крупных и «поживших» конфигураций 1С программисты часто сталкиваются с необходимостью расширения функционала существующих документов. Одной из таких задач является добавление новых регистров в список движений документа. Казалось бы, это простое изменение метаданных, но на практике система ведет себя по-разному: в одних случаях обновление проходит мгновенно (динамически), а в других — платформа требует выгнать всех пользователей для проведения реструктуризации. Разберем подробно, почему так происходит и какая техническая логика стоит за этими процессами.
Проанализируем ситуацию с точки зрения того, как платформа 1С хранит данные на уровне SQL-сервера. Ключевым моментом здесь является поле Регистратор, которое присутствует в каждой таблице движений регистров накопления, сведений или бухгалтерии. Рассмотрим два сценария состояния регистра в конфигурации:
_RecorderRRef (или аналогичное) имеет фиксированный тип данных (обычно binary(16)). Платформа «знает», что в этом регистре могут быть записи только одного типа документа, поэтому ей не нужно хранить идентификатор типа документа в каждой строке таблицы._RecorderTRef. Это поле хранит идентификатор типа метаданных, чтобы система понимала, к какому именно виду документа относится ссылка _RecorderRRef.Выясним причину блокировки динамического обновления: Если вы добавляете второй регистратор к регистру, который до этого имел только один, платформа вынуждена выполнить команду ALTER TABLE для добавления новой колонки _RecorderTRef. Любое изменение физической структуры таблицы (добавление колонок, изменение типов существующих колонок) — это и есть реструктуризация. Именно поэтому в такой ситуации динамическое обновление («демоническое», как его называют в шутку) невозможно.
Если же у регистра уже было два или более регистратора, добавление третьего, четвертого и последующих не меняет физическую структуру таблицы в SQL. Поле _RecorderTRef уже существует, оно уже настроено на хранение составного типа. Платформа просто обновляет свои внутренние таблицы описания метаданных, что позволяет выполнить обновление без монопольного захвата базы.
Рассмотрим другие механизмы, которые могут накладывать вето на динамическое обновление при изменении движений документа. Даже если вопрос с составным типом поля решен, существуют связанные объекты метаданных.
Последовательности документов: Если регистр накопления входит в какую-либо последовательность, то при добавлении нового регистратора платформа обязана внести изменения в служебные таблицы этой последовательности. Это необходимо для корректного контроля границ последовательности при проведении нового типа документа. Такие изменения часто требуют реструктуризации служебных таблиц последовательностей.
Планы обмена (РИБ): Проанализируем ситуацию с распределенными информационными базами. Если регистр или документ участвуют в обмене с авторегистрацией, добавление связи между ними меняет логику работы таблиц регистрации изменений (таблицы с префиксом _Chng). Платформа должна гарантировать, что структура данных для миграции идентична на всех узлах. Чтобы избежать коллизий при выгрузке данных, система блокирует динамическое изменение состава движений в таких объектах.
Начиная с версии платформы 8.3.11, механизмы реструктуризации были существенно оптимизированы. Рассмотрим, что изменилось. Раньше любая реструктуризация подразумевала создание временной таблицы, копирование туда всех данных, удаление старой таблицы и переименование новой. Это был крайне долгий процесс.
Современные версии платформы стараются выполнять «минимальную» реструктуризацию. Например, если в базе включена возможность фоновой реструктуризации (доступно в версии CORP), некоторые операции могут выполняться почти незаметно для пользователей. Однако для обычных лицензий требование монопольного режима остается в силе, если затрагиваются критические поля СУБД.
Несмотря на то, что платформа иногда позволяет «пробросить» изменения в движениях динамически, проанализируем, почему этого стоит избегать в продуктивных базах. Проблема заключается в кэшировании метаданных на стороне сервера приложений и клиентских сеансов.
Когда вы добавляете регистр в движения документа, объект Metadata изменяется. После динамического обновления может возникнуть ситуация «рассинхрона»:
rphost) может хранить старую версию метаданных, для мониторинга которых можно использовать специализированные инструменты анализа кластера.Посмотрим на пример того, как это может выглядеть в коде при попытке программного обращения к новым движениям сразу после «удачного» динамического обновления:
// Этот код может упасть с ошибкой в сеансе, который не был обновлен
Попытка
НаборДвижений = Движения.НовыйДобавленныйРегистр;
НаборДвижений.Записать();
Исключение
Сообщить("Ошибка обращения к метаданным: " + ОписаниеОшибки());
КонецПопытки;
Подводя итог, разберем алгоритм действий для безопасного добавления регистров в движения, включая запуск процедур обработчиков обновления при необходимости:
Важный момент: если вы случайно обнаружили, что обновление «проскочило» динамически, обязательно проверьте работоспособность механизма корректировки движений (или того функционала, ради которого вносились правки). Ошибки кэша могут проявиться не сразу, а только при определенных действиях пользователей, что усложнит диагностику проблемы в будущем.