Как исправить ошибку CREATE UNIQUE INDEX terminated because a duplicate key was found при загрузке DT в MS SQL?

Программист 1С v8.3 (Управляемые формы) Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При переносе информационной базы из файлового режима в клиент-серверный вариант (MS SQL Server) через файл выгрузки .dt администраторы и разработчики нередко сталкиваются со сбоем импорта. Платформа прерывает загрузку сообщением об ошибке: Infobase loading error. Some data was not loaded into the Infobase, reason: Attempt to insert nonunique values into unique index, указывая на сбой создания уникального индекса CREATE UNIQUE INDEX terminated because a duplicate key was found.

Разберем детально механизм возникновения этой проблемы, расшифруем сигнатуру ошибки в СУБД и рассмотрим пошаговые сценарии ее гарантированного устранения.

Анатомия ошибки: почему файловая база работает, а в SQL не загружается?

Проанализируем техническую сторону процесса загрузки данных платформой 1С:Предприятие. При развертывании базы из дампа .dt платформа сначала создает структуру таблиц в СУБД без уникальных индексов (или с отключенными индексами). Затем выполняется потоковая массовая вставка строк (bulk insert). После завершения вставки данных платформа подает серверу СУБД команду построения индексов, включая уникальные: CREATE UNIQUE INDEX.

Если среди загруженных данных физически присутствуют повторяющиеся строки с одинаковым набором ключевых полей, Microsoft SQL Server отклоняет команду создания индекса и полностью откатывает транзакцию загрузки. В файловом формате (1CD) движок базы данных менее строг: при аварийных сбоях питания, обрывах соединений или падениях рабочих процессов внутренние индексы B-дерева могут разрушаться, в результате чего в таблице накапливаются дублирующиеся строки без блокировки работы пользователей.

Расшифровка сигнатуры дубликата ключа

Посмотрим на текст ошибки из журнала:

The duplicate key value is (Jan 19 4016 12:00PM, 0x000000aa, 0x944d001f3c2a35f111e5f56a1bd0b2e9, 1).

Имя объекта — dbo._AccRg349, имя индекса — _AccRg349_ByPeriod_TRN.

Выясним причину каждого элемента этой сигнатуры:

  1. Объект dbo._AccRg349: Это физическая таблица движений регистра бухгалтерии (не таблица итогов). Выяснить точное имя регистра в конфигурации можно с помощью метода ПолучитьСтруктуруХраненияБазыДанных().
  2. Индекс _AccRg349_ByPeriod_TRN: Составной уникальный индекс регистра бухгалтерии, обеспечивающий уникальность по полям: Период (_Period), Тип регистратора (_RecorderTRef), Ссылка регистратора (_RecorderRRef) и Номер строки (_LineNo).
  3. Значение Jan 19 4016 12:00PM: При использовании MS SQL со стандартным смещением 2000 лет реальная дата документа в 1С соответствует 19.01.2016 12:00:00.
  4. Значение 0x000000aa: Код типа метаданных регистратора (в шестнадцатеричном виде, 170 в десятичном формате).
  5. Значение 0x944d001f3c2a35f111e5f56a1bd0b2e9: Двоичный идентификатор GUID конкретного документа-регистратора.
  6. Значение 1: Номер строки движения (НомерСтроки).

Таким образом, в регистре бухгалтерии по одному и тому же документу образовались две или более записи с одинаковым периодом и одинаковым номером строки 1.

Пошаговое решение проблемы

Рассмотрим порядок действий для устранения конфликта уникальности в зависимости от доступных исходных данных.

Способ 1. Устранение ошибки через файловую базу и Тестирование и исправление (ТиИ)

Это самый быстрый и надежный способ, решающий проблему в подавляющем большинстве случаев:

  1. Развернем проблемный файл .dt в новую пустую файловую информационную базу. Так как файловая СУБД 1С более лояльна к дубликатам при импорте, загрузка выгрузки пройдет успешно.
  2. Запустим утилиту физической проверки целостности chdbfl.exe (находится в каталоге платформы bin), выберем файл 1Cv8.1CD и отметим флаг Исправлять обнаруженные ошибки. Это восстановит поврежденную структуру внутренних страниц файла.
  3. Откроем базу в режиме Конфигуратор и перейдем в меню Администрирование -> Тестирование и исправление...
  4. Включим обязательные переключатели:
    • Реиндексация таблиц информационной базы;
    • Проверка логической целостности информационной базы;
    • Проверка ссылочной целостности информационной базы;
    • Пересчет итогов.
    В блоке при наличии ссылочных ошибок выберем вариант Очищать ссылки, а при частичной потере данных — Удалять объект.
  5. Нажмем Выполнить. В процессе тестирования логической целостности платформа выявит строки с неуникальными ключами в регистре бухгалтерии и автоматически нормализует номера строк либо удалит фантомные дубли.
  6. После завершения тестирования выгрузим базу в новый файл .dt и выполним повторную загрузку в клиент-серверную базу на MS SQL Server.

Способ 2. Программный поиск и перезапись набора записей регистра

Если требуется точно локализовать документ без полного тестирования всей базы, найдем и перезапишем движения программно. Разберем код внешней обработки:


// Определим ссылку на документ по известному строковому представлению GUID
ИдентификаторGUID = Новый УникальныйИдентификатор("944d001f-3c2a-35f1-11e5-f56a1bd0b2e9");

// Ищем документ среди документов соответствующего типа или через универсальный запрос
СсылкаНаДокумент = Документы.ОперацияБух.ПолучитьСсылку(ИдентификаторGUID);

// Создаем набор записей регистра бухгалтерии с отбором по документу-регистратору
НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаДокумент);

// Считываем движения из базы данных
НаборЗаписей.Прочитать();

// Принудительно восстанавливаем уникальную сквозную нумерацию строк
Номер = 1;
Для Каждого Запись Из НаборЗаписей Цикл
    Запись.НомерСтроки = Номер;
    Номер = Номер + 1;
КонецЦикла;

// Перезаписываем набор с замещением существующих записей
НаборЗаписей.Записать(Истина);
Сообщить("Набор записей успешно перезаписан, дубли устранены.");

Метод Записать(Истина) очищает старые записи регистра по регистратору и записывает нормализованный набор, устраняя конфликт номеров строк в индексе _ByPeriod_TRN.

Рекомендации по предотвращению проблемы

Учитывая особенности работы платформы, обратим внимание на следующие правила:

  1. Механизм выгрузки в .dt предназначен исключительно для переноса данных между различными платформами СУБД (например, с файловой на MS SQL или PostgreSQL). Не используем выгрузку в .dt в качестве штатного резервного копирования промышленной базы. Для бэкапов серверных баз следует использовать средства MS SQL Server (регулярные полные и разностные бэкапы, бэкапы транзакционных логов).
  2. Перед выгрузкой рабочей базы в .dt для миграции всегда выполняем предварительную проверку: логическую реиндексацию и исправление ошибок штатными средствами конфигуратора.
  3. Для переноса между информационными базами без применения .dt используем обработку Выгрузка и загрузка данных XML либо штатные механизмы планов обмена. Загрузка через объектную модель 1С самостоятельно нормализует наборы движений при их записи.
← На главную