Как исправить ошибку «Невозможно вставить повторяющуюся ключевую строку в объект dbo.#tt» при обмене РИБ в 1С?

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

При выполнении обмена данными в распределенной информационной базе (РИБ) администраторы и разработчики могут столкнуться с критическим сбоем при вызове метода ПрочитатьИзменения(). В окне сообщений 1С или журнале регистрации появляется системная ошибка СУБД: «Попытка вставки неуникального значения в уникальный индекс: Microsoft SQL Server Native Client: Невозможно вставить повторяющуюся ключевую строку в объект "dbo.#tt..." с уникальным индексом "idx...". HRESULT=80040E2F, native=2601». Разберем природу этого сбоя, выясним, почему временной таблицы нет в базе данных после падения сеанса, и рассмотрим эффективные методы локализации и устранения проблемы.

Механизм возникновения ошибки во временных таблицах СУБД

В процессе загрузки пакета изменений платформа 1С:Предприятие помещает входящий поток сериализованных данных во временные таблицы Microsoft SQL Server. Эти таблицы создаются в служебной базе tempdb и имеют префикс #tt (например, dbo.#tt42), где числовая часть является динамическим суффиксом текущего сеанса. По этой причине найти такую таблицу вручную после аварийного завершения транзакции невозможно: локальная временная таблица уничтожается сервером СУБД сразу после разрыва или отката контекста выполнения.

Для ускорения сопоставления данных и контроля ссылочной целостности платформа автоматически генерирует уникальный индекс для временной таблицы. Ошибка с системным кодом native=2601 (SQLSTATE=23000) возникает тогда, когда в пределах одного загружаемого пакета или одной транзакции оказываются две или более записи с полностью совпадающим первичным ключом. В зависимости от типа метаданных дублирование может возникнуть в следующих элементах:

  1. Регистры сведений: совпадение комбинации всех измерений (а для периодических регистров — дополнительно даты периода).
  2. Табличные части объектов: дублирование системного номера строки или ключевого поля связи.
  3. Таблицы итогов регистров накопления и бухгалтерии: совпадение периода формирования итогов, регистратора и набора аналитических разрезов (измерений).

Основные причины появления дубликатов в пакете обмена

Проанализируем типовые ситуации, приводящие к формированию некорректного файла обмена:

  1. Запись одинаковых движений несколькими документами: два разных документа в узле-источнике формируют одинаковые записи в периодический регистр сведений на одну и ту же дату и секунду с идентичным набором измерений.
  2. Игнорирование режима загрузки в коде конфигурации: если в модулях объектов или подписках на события (например, ПередЗаписью или ПриЗаписи) разработчик не установил проверку системного флага загрузки, при импорте начинает повторно выполняться прикладная логика. В результате платформа пытается повторно рассчитать или сгенерировать подчиненные данные, что порождает дубли.
  3. Коллизии одновременного редактирования: если один и тот же объект был изменен одновременно в центральном и периферийном узлах, стандартные правила разрешения коллизий РИБ могут некорректно объединить строки табличных частей.
  4. Нарушение целостности итогов: при сбоях в таблицах итогов регистров накопления формируются некорректные свернутые данные, конфликтующие с индексами узла-приемника.

Точные методы диагностики коллизий

Вместо полного перебора базы вручную воспользуемся профессиональными инструментами анализа:

  1. Настройка Технологического журнала (ТЖ): настроим сбор событий EXCP и DBMSSQL. В момент падения обмена журнал зафиксирует точный SQL-запрос к таблице #tt с перечнем системных полей. По именам этих полей с помощью функции ПолучитьСтруктуруХраненияБазыДанных() можно мгновенно определить проблемный регистр или справочник 1С.
  2. Трассировка средствами MS SQL Server: настроим сессию Extended Events (или SQL Server Profiler) с фильтром по событию Exception и коду ошибки 2601. Это позволит перехватить конкретный SQL-батч и значения строк прямо в момент нарушения уникальности индекса.
  3. Анализ XML-файла выгрузки: откроем сформированный файл обмена и выполним поиск повторяющихся блоков внутри тегов <RecordSet> или <v8:Record>.

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

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

Шаг 1. Локализация проблемных данных методом деления регистрации

Если нет возможности настроить технологический журнал, применим метод изолированной регистрации:

  1. В главном узле полностью очистим регистрацию изменений для проблемного периферийного узла с помощью стандартной обработки «Регистрация изменений для обмена».
  2. Зарегистрируем данные порциями по типам метаданных (сначала справочники, затем документы, затем регистры сведений).
  3. Выполняем обмен после каждой порции. Как только обмен упадет на конкретном типе метаданных, регистрируем документы небольшими пачками дат, пока не выявим конкретный документ-виновник.

Шаг 2. Устранение коллизии в периодическом регистре

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

Шаг 3. Корректировка программного кода

Проверим все подписки на события и модули наборов записей. Любая прикладная генерация движений должна блокироваться при загрузке обмена:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    // Обязательная проверка флага обмена данными
    Если ЭтотОбъект.ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;
    
    // Прикладной алгоритм формирования движений
    СформироватьСлужебныеДвижения();
КонецПроцедуры

Шаг 4. Программная фильтрация в плане обмена

Для предотвращения аварийной остановки обмена при повторении подобных ситуаций можно добавить программный перехват в модуль плана обмена в обработчик события ПриПолученииДанныхОтГлавного (или ПриПолученииДанныхОтПодчиненного):


Процедура ПриПолученииДанныхОтГлавного(ЭлементДанных, ПолучениеЭлемента, ОтправитьНазад)
    // Проверяем тип входящих данных
    Если ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КурсыВалют") Тогда
        // При необходимости выполняем валидацию или предварительное чтение
        // для предотвращения коллизий уникальности
    КонецЕсли;
КонецПроцедуры

Шаг 5. Полный пересчет итогов

В обеих базах (источнике и приемнике) выполним операцию «Тестирование и исправление» с обязательным пунктом «Пересчет итогов» либо выполним полное отключение и повторный расчет итогов через управление итогами в режиме предприятия. Это устранит возможные скрытые рассинхронизации агрегатных таблиц перед повторной отправкой пакета.

← На главную