Как исправить ошибку «Попытка вставки неуникального значения в уникальный индекс» при обновлении базы 1С?

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

При обновлении или реструктуризации большой информационной базы в клиент-серверном варианте администраторы и разработчики нередко сталкиваются с критической ошибкой: «Нарушено условие уникальности данных. Попытка вставки неуникального значения в уникальный индекс». Особенно неприятно, когда ошибка указывает на таблицу с суффиксом NG (например, _DocumentJournal28036NG) и происходит в процессе создания уникального индекса. Ситуация осложняется тем, что стандартная выгрузка в файловый вариант (dt) для исправления часто невозможна из-за огромного объема данных.

В этой статье мы подробно разберем, почему возникает эта ошибка, как расшифровать сообщение SQL Server и какие шаги необходимо предпринять для восстановления работоспособности базы, используя инструменты SQL и знания о внутренней структуре 1С.

Понимаем природу ошибки и суффикса NG

Для начала проанализируем, что именно происходит в момент ошибки. Когда платформа 1С выполняет реструктуризацию таблицы (например, при изменении состава журнала документов или добавлении реквизита в расширение), она не меняет основную таблицу напрямую. Вместо этого создается временная таблица с суффиксом NG (Next Generation). Платформа переносит данные из старой таблицы в новую, после чего пытается создать индексы. Если в переносимых данных оказываются дубли по полям, входящим в уникальный индекс, SQL Server прерывает операцию CREATE UNIQUE INDEX.

Наличие в ошибке букв NG в имени таблицы — это прямой признак того, что сбой произошел именно в процессе «переезда» данных в новую структуру. Если процесс прервался, эта временная таблица может остаться в базе данных, мешая последующим попыткам обновления.

Шаг 1. Расшифровка «виновника» по значению ключа

В тексте ошибки SQL обычно указывает конкретное повторяющееся значение ключа. Например: (0, 0x000002aa, 0x818fc8d3a384789d11eb6239840abf1b). Разберем, что скрывается за этими шестнадцатеричными числами:

  1. 0 — это техническое поле (может быть разделителем данных или признаком удаления).
  2. 0x000002aa — это поле _DocumentTRef. Оно определяет тип документа. Чтобы перевести его в понятный вид, отбросим 0x и преобразуем 2AA из шестнадцатеричной системы в десятичную — получаем 682.
  3. 0x818fc8d3... — это поле _DocumentRRef. Это уникальный идентификатор (GUID) конкретного документа в базе данных.

Чтобы выяснить, какой именно тип документа вызывает проблему, выполним запрос в SQL Server Management Studio (SSMS) к таблице метаданных:


SELECT * FROM [dbo].[_MetadataId] 
WHERE [_TypeID] = 2 AND [_Tid] = 682

Здесь _TypeID = 2 указывает на то, что мы ищем среди документов, а _Tid — это наше число 682. В результате мы получим имя таблицы документа, который породил дубль в журнале.

Шаг 2. Поиск дублей в журнале документов через SQL

Теперь нам нужно найти записи, которые платформа считает одинаковыми. Рассмотрим пример запроса для поиска дублей в конкретном журнале (в нашем случае это _DocumentJournal28036). Мы будем искать записи, у которых совпадают тип документа и его ссылка.

Выполним следующий запрос для диагностики:


SELECT [_DocumentTRef] AS RefType, 
       [_DocumentRRef] AS Ref, 
       COUNT(*) as CountOfDuplicates
FROM [dbo].[_DocumentJournal28036] WITH (NOLOCK)
GROUP BY [_DocumentTRef], [_DocumentRRef]
HAVING COUNT(*) > 1

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


SELECT * FROM [dbo].[_DocumentJournal28036] 
WHERE [_DocumentRRef] = 0x818fc8d3a384789d11eb6239840abf1b

Шаг 3. Проблема «призрачных» записей в расширениях

Часто ошибка связана не с самой основной базой, а с механизмом расширений. Платформа 1С для хранения данных расширений создает дополнительные таблицы с суффиксами вроде X1. Если вы изменили состав журнала в расширении, 1С может ошибочно пытаться объединить данные основной таблицы и таблицы расширения, получая дубли по ссылкам.

Рассмотрим алгоритм проверки таблиц расширений:

  1. Выясняем имя таблицы документа (например, _Document332) через _MetadataId.
  2. Проверяем наличие таблицы расширения для этого документа (например, _Document332X1).
  3. Сравниваем количество записей в основной таблице и таблице расширения:

SELECT COUNT(*) FROM _Document332;
SELECT COUNT(*) FROM _Document332X1;

Проанализируем ситуацию: если в обеих таблицах есть данные по одной и той же ссылке, это и есть причина конфликта. В некоторых случаях (согласно опыту коллег) помогает полная очистка таблицы расширения, если данные в ней дублируют основную базу, командой TRUNCATE TABLE _Document332X1, но делать это можно только после тщательного анализа и создания бэкапа!

Шаг 4. Временное отключение расширений и смена платформы

Если поиск и удаление дублей через SQL не помогают или дубли появляются вновь при каждой попытке обновления, велика вероятность, что мы столкнулись с зарегистрированной ошибкой платформы (например, ошибка 10235932). В этом случае рассмотрим альтернативные варианты решения:

Вариант А: Манипуляции с расширениями. Попробуем временно отключить или удалить расширение, которое вносит изменения в структуру проблемного журнала или справочника. В ряде случаев достаточно сделать расширение «неактивным», провести обновление конфигурации базы данных, а затем снова включить его.

Вариант Б: Смена версии платформы. Механизм реструктуризации значительно менялся в версиях 8.3.21, 8.3.22 и выше. Иногда «оптимизированная реструктуризация» работает некорректно с конкретными данными. Как показывает практика, если обновление падает на 8.3.24, имеет смысл попробовать выполнить его на более старой, стабильной ветке (например, 8.3.21), а после успешного завершения вернуться на актуальную версию.

Шаг 5. Исправление данных (Удаление дублей)

Если вы точно установили, что в таблице журнала присутствуют две абсолютно идентичные записи с одинаковыми _DocumentTRef и _DocumentRRef, одну из них придется удалить напрямую через SQL. Внимание! Это крайняя мера. Перед любыми действиями по удалению обязательно создайте резервную копию базы данных.

Пример безопасного подхода:

  1. Найдите CTID или другой внутренний идентификатор строки (в SQL Server можно использовать row_number()), чтобы отличить одну запись от другой.
  2. Удалите только одну строку, оставив вторую нетронутой.
  3. После этого запустите «Тестирование и исправление» в конфигураторе с галками «Проверка логической целостности» и «Пересчет итогов».

Рассмотрим пример запроса для удаления дублей, оставляя только одну запись с минимальным системным идентификатором (если он есть):


WITH CTE AS (
    SELECT TOP 100 * -- всегда проверяйте выборку перед удалением!
    FROM [dbo].[_DocumentJournal28036]
    WHERE [_DocumentRRef] = 0x818fc8d3a384789d11eb6239840abf1b
)
-- DELETE FROM CTE; -- Раскомментируйте после проверки

Резюме и рекомендации

Подведем итог нашему исследованию. Ошибка уникальности индекса в таблицах NG — это сложная техническая проблема, требующая понимания структуры SQL-таблиц 1С. Для её решения мы:

Помните, что работа напрямую с таблицами SQL — это вмешательство в механизмы платформы. Всегда начинайте с простых методов: очистки кэша сервера 1С, тестирования и исправления, и только в случае неудачи переходите к прямым SQL-запросам. Для автоматизации регулярного резервного копирования, проверки и технического обслуживания баз можно использовать программу для автоматического тестирования, архивирования и обновления 1С.

← На главную