При переходе между релизами конфигураций через большой интервал версий разработчики часто сталкиваются с критическим сбоем обновления на этапе реструктуризации таблиц. В СУБД Microsoft SQL Server генерируется исключение: The CREATE UNIQUE INDEX statement terminated because a duplicate key was found. Ошибка сообщает о попытке создания уникального индекса для временной таблицы с суффиксом NG (например, _AccumRgT7440NG) по набору измерений _ByDims, содержащему дублирующиеся данные.
Проанализируем природу этой ошибки, выясним, почему стандартный поиск данных в пользовательском интерфейсе 1С не дает результатов, и подробно разберем по шагам надежные способы устранения проблемы.
Рассмотрим структуру диагностического сообщения, которое выдает сервер СУБД. Понимание формата представления данных в 1С на уровне SQL позволяет сразу локализовать источник проблемы:
_AccumRgT указывает на то, что сбой произошел не в таблице движений регистра накопления (которая обозначается как _AccumRg), а в физической таблице итогов (остатков). Постфикс NG означает новую версию таблицы, которую платформа создает в процессе реструктуризации для копирования и конвертации данных.Jan 1 4012 12:00AM часто вводит в заблуждение. При создании баз данных на MS SQL Server платформа 1С по умолчанию применяет смещение дат на 2000 лет вперед для корректной работы со старыми форматами времени. Таким образом, год 4012 соответствует 2012 году в терминах 1С (4012 минус 2000).12:00 AM обозначает полночь, то есть 00:00:00. Таблицы итогов регистров накопления хранят агрегированные остатки на начало каждого месяца. Соответственно, дублирующаяся запись сформирована на момент 01.01.2012 00:00:00, а не на середину дня.2.44) указывают на числовые измерения или разделители.Основная причина появления дублей при прыжке через десятки релизов — изменение состава или свойств измерений регистра (например, удаление измерения, изменение длины строкового поля или уменьшение точности числа). При копировании старых записей во временную таблицу NG значения, которые раньше различались по удаленному полю, становятся полностью идентичными, что и приводит к нарушению уникальности индекса _ByDims.
Поскольку ошибка локализована исключительно в таблице итогов (_AccumRgT), а сами первичные движения в регистре уникальны, самым простым и безопасным способом является полное отключение использования итогов перед запуском реструктуризации.
Разберем по шагам выполнение этой операции:
Структура = ПолучитьСтруктуруХраненияБазыДанных();
Для Каждого Стр Из Структура Цикл
Если Стр.ИмяТаблицыХранения = "_AccumRg7440"
Или Стр.ИмяТаблицыХранения = "_AccumRgT7440" Тогда
Сообщить("Имя метаданных: " + Стр.Имя);
КонецЕсли;
КонецЦикла;
ЗаказыПоставщикам):
РегистрыНакопления.ЗаказыПоставщикам.УстановитьИспользованиеИтогов(Ложь);
Также можно воспользоваться стандартной обработкой «Управление итогами» и снять использование итогов для всей базы или конкретного регистра.УстановитьИспользованиеИтогов(Ложь) платформа физически очищает таблицу итогов в базе данных.
РегистрыНакопления.ЗаказыПоставщикам.УстановитьИспользованиеИтогов(Истина);
РегистрыНакопления.ЗаказыПоставщикам.ПересчитатьИтоги();
Если необходимо локализовать конкретные элементы справочников, входящие в дублирующуюся запись, разберем, как получить ссылки 1С из бинарных данных MS SQL Server.
Формат хранения UUID в СУБД отличается порядком следования байтов от стандартного строкового представления 1С. Чтобы найти объект без сложных побайтовых преобразований, выполним прямой запрос в Microsoft SQL Server Management Studio к таблице предполагаемого справочника (например, номенклатуры):
SELECT _IDRRef, _Code, _Description
FROM dbo._ReferenceXXX
WHERE _IDRRef = 0xa5be000423cce2e311e10eadfe8bd2d5;
Также можно преобразовать бинарную строку во внутренний формат 1С программно с помощью подмены пустой ссылки через метод ЗначениеИзСтрокиВнутр:
// Внутреннее представление пустой ссылки содержит 32 нуля
ВремСтрока = ЗначениеВСтрокуВнутр(Справочники.Номенклатура.ПустаяСсылка());
// Подставляем hex-значение из ошибки без префикса 0x
ВремСтрока = СтрЗаменить(ВремСтрока, "00000000000000000000000000000000", "a5be000423cce2e311e10eadfe8bd2d5");
СсылкаНаОбъект = ЗначениеИзСтрокиВнутр(ВремСтрока);
Сообщить("Найден объект: " + Строка(СсылкаНаОбъект));
В ситуациях, когда движения регистра были очищены, но в таблице итогов остались «фантомные» записи из-за нарушения целостности базы, очистим таблицу итогов напрямую в СУБД. Таблицы итогов являются агрегатами, и их очистка не приводит к потере первичных учетных документов.
Выполним в Management Studio команды:
-- Очищаем таблицу итогов проблемного регистра
TRUNCATE TABLE dbo._AccumRgT7440;
-- Если после предыдущей аварийной реструктуризации осталась временная таблица NG, удаляем ее
IF OBJECT_ID('dbo._AccumRgT7440NG', 'U') IS NOT NULL
DROP TABLE dbo._AccumRgT7440NG;
После очистки таблицы запустим обновление конфигурации из конфигуратора 1С. После завершения обновления выполним операцию Тестирование и исправление информационной базы с установленным флагом Пересчет итогов.
Если специфика SQL-сервера блокирует процесс создания промежуточных индексов, применим обходной технологический прием:
.dt)..dt и загрузим ее в рабочую базу на MS SQL Server.Важное ограничение: данный способ применим только в том случае, если размер любой из таблиц базы данных не превышает технологическое ограничение файлового формата 1С (4 Гб на одну таблицу внутри файла базы данных 1Cv8.1CD).