При обновлении крупных прикладных решений на платформе «1С:Предприятие 8.3», таких как «1С:Комплексная автоматизация 2.4» или «1С:ERP Управление предприятием», администраторы и разработчики часто сталкиваются со сбоями в процессе реструктуризации базы данных. Одним из наиболее критических является сбой СУБД с ошибкой: «Попытка вставки неуникального значения в уникальный индекс».
В этой статье мы подробно разберем, почему возникает эта ошибка на стороне MS SQL Server, как устроена структура таблиц платформы 1С и какими инструментами можно диагностировать и устранить эту неисправность, чтобы успешно завершить обновление информационной базы.
Для начала проанализируем системное сообщение СУБД:
Не удается вставить повторяющуюся строку ключа в объект "dbo._Reference75NG" с уникальным индексом "_Reference75HPKNG". Повторяющееся значение ключа: (0, 0x80eb95b2f361150f11e9076a0727b60e).
Выясним назначение суффиксов и индексов, фигурирующих в ошибке:
NG (Next Generation): Платформа 1С при изменении структуры метаданных не модифицирует рабочую таблицу (например, _Reference75) напрямую. Вместо этого создается ее временная копия с суффиксом NG (_Reference75NG). В нее переносятся все данные, затем на ней строятся новые индексы, после чего старая таблица удаляется, а новая переименовывается. Если на этапе переноса данных происходит сбой, транзакция откатывается.HPK (Hierarchical Primary Key): Этот индекс создается для иерархических справочников (в нашем случае это справочник «Виды контактной информации»). Он представляет собой уникальный составной кластерный индекс СУБД, состоящий из двух полей: _Folder (определяет тип записи: 0 — элемент, 1 — группа) и _IDRRef (уникальный идентификатор GUID элемента в бинарном формате).(0, 0x80eb95b2f361150f11e9076a0727b60e) указывает на то, что дубликатом является обычный элемент справочника (не группа, так как первый параметр равен 0), а второй параметр — это шестнадцатеричное представление уникального идентификатора (UUID) записи, которая дублируется в таблице.Казалось бы, если в 1С настроена уникальность идентификаторов, то как физически в СУБД могут появиться две строки с одинаковым GUID? Проанализируем основные причины:
Поскольку платформа 1С при возникновении ошибки откатывает транзакцию и удаляет временную таблицу с суффиксом NG, мы не сможем найти дубликаты непосредственно в таблице _Reference75NG. Нам необходимо исследовать основную рабочую таблицу справочника — _Reference75.
Шаг 1. Определим, какому объекту метаданных 1С соответствует SQL-таблица.
Если вы хотите точно убедиться, какой именно справочник скрывается под именем _Reference75, выполним следующий код в консоли кода 1С:
ИмяТаблицы = ПолучитьСтруктуруХраненияБазыДанных().Найти("_Reference75", "ИмяТаблицыХранения");
Если ИмяТаблицы <> Неопределено Тогда
Сообщить("Объект метаданных: " + ИмяТаблицы.ИмяМетаданных);
КонецЕсли;
Обычно таблица _Reference75 в КА 2.4 соответствует справочнику ВидыКонтактнойИнформации.
Шаг 2. Выполним поиск дублирующихся записей в SQL Server Management Studio (SSMS).
Подключимся к СУБД, откроем окно создания запроса для нашей базы данных и выполним группировочный запрос, чтобы выявить записи с одинаковым уникальным идентификатором _IDRRef:
SELECT _IDRRef, COUNT(*) AS Qty
FROM dbo._Reference75
GROUP BY _IDRRef
HAVING COUNT(*) > 1;
Если этот запрос возвращает строки, значит, в рабочей таблице действительно присутствуют физические дубликаты.
Шаг 3. Детально проанализируем найденные дубликаты.
Для того чтобы посмотреть конкретное содержимое конфликтующих записей, выполним запрос по конкретному GUID, который был указан в тексте ошибки (в формате SQL шестнадцатеричное значение записывается без дефисов):
SELECT *
FROM dbo._Reference75
WHERE _IDRRef = 0x80EB95B2F361150F11E9076A0727B60E;
Проанализируем полученный результат. Мы увидим две строки с абсолютно одинаковым идентификатором. Обратим внимание на поля _Description (Наименование), _PredefinedID (Идентификатор предопределенного элемента) и другие служебные поля, чтобы понять природу происхождения дублей.
Существует несколько путей исправления этой ситуации в зависимости от причин ее возникновения. Рассмотрим их подробно.
Если мы локализовали дублирующиеся строки и убедились, что они мешают реструктуризации, нам необходимо физически удалить одну из конфликтующих строк.
Важно: Перед выполнением любых деструктивных операций на уровне SQL Server обязательно создайте резервную копию базы данных! Прямое редактирование таблиц СУБД производится на собственный страх и риск для аварийного восстановления работоспособности базы.
Разберем, как безопасно удалить дублирующуюся запись, оставив только одну. Если строки полностью идентичны, мы можем воспользоваться механизмом обобщенных табличных выражений (CTE) в T-SQL. Выполним следующий скрипт:
WITH CTE_Duplicates AS (
SELECT _IDRRef,
ROW_NUMBER() OVER (PARTITION BY _IDRRef ORDER BY (SELECT NULL)) AS RowNum
FROM dbo._Reference75
WHERE _IDRRef = 0x80EB95B2F361150F11E9076A0727B60E
)
DELETE FROM CTE_Duplicates
WHERE RowNum > 1;
Этот запрос пронумерует строки с одинаковым _IDRRef и удалит все строки, порядковый номер которых больше 1, оставив ровно одну уникальную запись. После этого индекс СУБД сможет быть успешно построен.
Если в справочнике обнаружено много дубликатов, мы можем применить этот скрипт ко всей таблице целиком (без фильтрации по конкретному GUID):
WITH CTE_AllDuplicates AS (
SELECT _IDRRef,
ROW_NUMBER() OVER (PARTITION BY _IDRRef ORDER BY (SELECT NULL)) AS RowNum
FROM dbo._Reference75
)
DELETE FROM CTE_AllDuplicates
WHERE RowNum > 1;
После успешного удаления дубликатов попробуем запустить процесс обновления конфигурации базы данных в режиме Конфигуратора 1С еще раз.
Если в процессе анализа мы обнаружили, что дубликатов физически нет, но ошибка все равно возникает, либо если мы подозреваем логические разрушения структуры файлов базы данных на диске СУБД, необходимо выполнить проверку целостности.
Запустим в среде SSMS проверку базы данных с помощью команды DBCC CHECKDB:
DBCC CHECKDB ('Имя_Вашей_Базы_Данных') WITH NO_INFOMSGS, ALL_ERRORMSGS;
Внимательно изучим отчет команды в консоли сообщений. Если СУБД сообщает об ошибках согласованности или повреждении страниц данных, нам потребуется выполнить восстановление. Если ошибки критические, рекомендуется перевести базу в однопользовательский режим и запустить процедуру исправления индексов:
ALTER DATABASE Имя_Вашей_Базы_Данных SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO
DBCC CHECKDB ('Имя_Вашей_Базы_Данных', REPAIR_REBUILD);
GO
ALTER DATABASE Имя_Вашей_Базы_Данных SET MULTI_USER;
GO
Параметр REPAIR_REBUILD выполняет безопасное восстановление без риска потери данных.
При аварийном завершении реструктуризации (например, если отключился сервер или процесс Конфигуратора был завершен принудительно через диспетчер задач) в базе данных могут остаться «зависшие» временные таблицы с суффиксами _NG или _Q. Эти таблицы занимают дисковое пространство и могут мешать последующим попыткам реструктуризации.
Выясним, есть ли в нашей базе такие таблицы. Для этого в SSMS выполним системный запрос:
SELECT name
FROM sys.tables
WHERE name LIKE '%NG' OR name LIKE '%Q';
Если мы обнаружили таблицы типа _Reference75NG, которые остались после завершения работы всех пользователей и закрытия Конфигуратора, мы можем безопасно удалить их вручную с помощью команды DROP TABLE:
DROP TABLE dbo._Reference75NG;
Убедимся перед удалением, что в базе никто не работает, и процесс обновления остановлен.
Иногда проблема дублирования предопределенных элементов вызвана ошибками релиза самой платформы 1С. Фирма «1С» регулярно выпускает исправления технологической платформы, устраняющие некорректное поведение при реструктуризации и сопоставлении метаданных.
Если вы используете устаревшую версию платформы (например, одну из ранних версий линейки 8.3.12–8.3.15), настоятельно рекомендуется обновить платформу сервера 1С и клиентских приложений до актуального стабильного релиза. Обновление платформы перед реструктуризацией базы данных часто позволяет избежать множества ошибок СУБД.
Чтобы минимизировать риски возникновения ошибок уникальности индексов при последующих обновлениях «1С:Комплексная автоматизация» или других тяжелых конфигураций, придерживайтесь следующих правил: