При обновлении крупных конфигураций, таких как 1С:Комплексная автоматизация 2 или 1С:ERP, администраторы и программисты часто сталкиваются с ошибками реструктуризации базы данных. Одной из самых неприятных является ошибка, связанная с регистром сведений ВерсииОбъектов. Система сообщает о наличии дублирующихся записей, что не позволяет завершить переход на новый релиз. Ситуация осложняется тем, что стандартные запросы часто не показывают видимых дублей.
В этой статье мы подробно разберем, почему возникают «невидимые» дубли, как их диагностировать и какими способами можно очистить регистр, чтобы успешно продолжить обновление. Чтобы автоматизировать обслуживание и проверку системы при переходе на новые релизы, можно использовать автоматическое обновление и архивирование баз 1С.
Регистр сведений ВерсииОбъектов является независимым и непериодическим. Его уникальность определяется измерениями Объект и НомерВерсии. Казалось бы, появление дублей в такой структуре невозможно на логическом уровне 1С, однако на практике это происходит по нескольким причинам:
Объект могут находиться записи со значением «Объект не найден». Если таких записей несколько с одинаковыми номерами версий, при реструктуризации СУБД (например, MS SQL Server) не может создать уникальный индекс.Если стандартный запрос по группировке не дает результатов, проанализируем ситуацию глубже. Попробуем найти записи, где объект не определен или ссылается на удаленный элемент (битая ссылка). Рассмотрим следующий запрос:
ВЫБРАТЬ
ВерсииОбъектов.Объект КАК Объект,
ВерсииОбъектов.НомерВерсии КАК НомерВерсии,
КОЛИЧЕСТВО(*) КАК КоличествоЗаписей
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
СГРУППИРОВАТЬ ПО
ВерсииОбъектов.Объект,
ВерсииОбъектов.НомерВерсии
ИМЕЮЩИЕ
КОЛИЧЕСТВО(*) > 1
Если этот запрос пуст, проанализируем наличие записей с «битыми» ссылками. Выясним причину через проверку типа объекта:
ВЫБРАТЬ
ВерсииОбъектов.Объект,
ВерсииОбъектов.НомерВерсии
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.Объект.Ссылка ЕСТЬ NULL
И ВерсииОбъектов.Объект <> ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка) // Проверьте основные типы
Важный момент: Если в технологическом журнале (ТЖ) зафиксирована ошибка Primary Key Violation, там часто указан конкретный идентификатор (GUID). Попробуйте найти запись в базе именно по этому GUID, используя консоль запросов.
Прежде чем переходить к радикальным мерам, попробуем воспользоваться штатным функционалом Библиотеки стандартных подсистем (БСП), которая встроена в КА 2.4. В программе предусмотрено регламентное задание для очистки устаревших версий.
Разберем, как это настроить:
Если нам нужно запустить очистку программно и принудительно, мы можем использовать метод программного интерфейса:
// Вызов в контексте серверного модуля или внешней обработки
ВерсионированиеОбъектов.ОчиститьУстаревшиеВерсииОбъектов();
Этот метод хорош тем, что он удаляет данные порциями, не вызывая переполнения лога транзакций и не блокируя таблицу на длительное время. Для решения этой задачи также подойдёт обработка для удаления устаревших версий объектов в КА и ERP.
Часто база «пухнет» из-за того, что пользователи нажимают «Провести и закрыть» в документах, не внося никаких изменений. В регистре создаются идентичные копии данных. Разберем алгоритм, как найти и «почикать» такие дубли по содержанию:
ХранилищеЗначения из ресурса ВерсияОбъекта.Посмотрим на пример кода для удаления дублей содержания:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВерсииОбъектов.Объект КАК Объект,
| ВерсииОбъектов.НомерВерсии КАК НомерВерсии
|ИЗ
| РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
|УПОРЯДОЧИТЬ ПО
| Объект,
| НомерВерсии";
Выборка = Запрос.Выполнить().Выбрать();
ТекущийОбъект = Неопределено;
ПредыдущийХеш = "";
Пока Выборка.Следующий() Цикл
Если ТекущийОбъект <> Выборка.Объект Тогда
ТекущийОбъект = Выборка.Объект;
ПредыдущийХеш = "";
КонецЕсли;
// Здесь должна быть логика извлечения данных из ХранилищаЗначения
// и сравнение Хеша. Если Хеш совпал с ПредыдущийХеш:
// Набор = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
// Набор.Отбор.Объект.Установить(Выборка.Объект);
// Набор.Отбор.НомерВерсии.Установить(Выборка.НомерВерсии);
// Набор.Записать();
КонецЦикла;
Если регистр содержит миллионы записей (например, 25 000 000+), а обновление критично запустить «вчера», самым эффективным способом будет полная очистка регистра. Помните, что при этом вся история изменений объектов будет удалена, но сами объекты останутся нетронутыми. Для планового сокращения объема исторических данных в крупных информационных системах применяется многопоточная свёртка 1С:ERP.
Проанализируем способы быстрой очистки:
Если база работает в файловом режиме или вы не имеете доступа к SQL-консоли, используйте пустой набор записей:
Набор = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
// Отбор не устанавливаем, чтобы очистить весь регистр
Набор.Записать();
Это самый быстрый способ. Выясним имя таблицы в СУБД (через функцию ПолучитьСтруктуруХраненияБазыДанных) и выполним команду TRUNCATE TABLE. Это мгновенно освободит место и удалит все записи без записи каждой операции в лог транзакций.
Важно: После выполнения TRUNCATE на уровне SQL обязательно выполните Тестирование и исправление (ТИИ) в конфигураторе 1С (пункты «Реиндексация таблиц» и «Проверка логической целостности»), чтобы платформа корректно восприняла изменения в физической структуре.
Мы рассмотрели различные подходы к решению проблемы с дублями в регистре версий. Если ваша задача — просто «проскочить» обновление, наиболее разумным будет полная или частичная очистка регистра за старые периоды. Если же история версий жизненно необходима, сфокусируйтесь на поиске битых ссылок и проверке физической целостности БД через SQL-запросы или технологический журнал.
Рекомендуем также настроить регламентное задание очистки версий сразу после успешного перехода на новый релиз, чтобы предотвратить раздувание базы в будущем.