Перевод информационной базы 1С:Предприятие из файлового режима (формат .1CD) в клиент-серверный вариант под управлением СУБД (MS SQL Server, PostgreSQL, IBM DB2) — стандартная процедура при росте нагрузки и увеличении объема данных. Однако в процессе загрузки файла резервной копии (.dt) системные администраторы и разработчики часто сталкиваются с критической ошибкой: «Попытка вставки неуникального значения в уникальный индекс» (в терминологии SQL-сервера это ошибки с кодами 1505 и 2601). Транзакция создания базы данных аварийно прерывается, и процесс загрузки останавливается.
В этой статье мы подробно разберем, почему возникает этот сбой, как локализовать проблемную таблицу и какими методами можно гарантированно устранить дублирование данных как на стороне платформы 1С, так и непосредственно в СУБД.
Файловая СУБД 1С (движок базы данных встроенный в платформу) работает по менее строгим правилам контроля уникальности физических индексов на низком уровне, нежели промышленные СУБД. В результате аварийного завершения работы пользователей, сбоев сетевого оборудования во время транзакций или некорректно выполненных обменов данными (например, в распределенных информационных базах — РИБ) в таблицах файлового файла 1Cv8.1CD могут появиться физически задублированные строки. Визуально в режиме «1С:Предприятие» это может никак не проявляться.
При выгрузке данных в файл .dt платформа упаковывает информацию последовательно, игнорируя физические индексы. Но как только мы запускаем процесс загрузки .dt в клиент-серверную базу, SQL-сервер начинает жестко выстраивать структуру таблиц и выполнять SQL-команду CREATE UNIQUE INDEX (создание уникального индекса). Наткнувшись на две абсолютно идентичные по ключевым полям строки, СУБД отвергает команду вставки, генерируя ошибку уровня HRESULT=80040E2F.
Обычно сбой происходит в таблицах итогов регистров накопления (имена таблиц вида _AccumRegTotals...), регистрах сведений (_InfoRg...) или таблицах регистрации изменений для планов обмена (_ChngR...).
Прежде чем приступать к лечению базы, нам необходимо понять, в какой именно таблице содержатся дубликаты. Проанализируем типичный текст ошибки из технологического журнала или окна выгрузки:
The CREATE UNIQUE INDEX statement terminated because a duplicate key was found for the object name 'dbo._AccumRegTotals4445' and the index name '_AccumR4445_ByDims_TRRRRR'. The duplicate key value is (Jan 1 2001 12:00AM, 0x00000000000000000000000000000000, ...)
Из этого сообщения мы можем извлечь важнейшие сведения:
_AccumRegTotals4445 (это таблица итогов регистра накопления)._AccumR4445_ByDims_TRRRRR (уникальный индекс по измерениям регистра).Jan 1 2001 и набор пустых уникальных идентификаторов (GUID) вида 0x00000000000000000000000000000000.Теперь нам нужно сопоставить физическое имя таблицы СУБД с логическим объектом метаданных в конфигурации 1С. Для этого в режиме «1С:Предприятие» мы можем использовать программный метод ПолучитьСтруктуруХраненияБазыДанных(). Запустим внешнюю обработку со следующим кодом:
СтруктураБазы = ПолучитьСтруктуруХраненияБазыДанных();
Для Каждого Таблица Из СтруктураБазы Цикл
Если Таблица.ИмяТаблицыХранения = "_AccumRegTotals4445" Тогда
Сообщить("Сбойная таблица принадлежит объекту: " + Таблица.Метаданные);
Прервать;
КонецЕсли;
КонецЦикла;
Выполнив этот код, мы выясним, например, что таблица _AccumRegTotals4445 соответствует регистру накопления ТоварыНаСкладах.
Самый безопасный и правильный способ решения проблемы — исправить данные в исходной файловой базе до момента ее экспорта в SQL. Рассмотрим основные методы лечения по шагам.
Стандартный механизм проверки логической и ссылочной целостности базы данных может помочь очистить «битые» записи. Запустим конфигуратор файловой базы и перейдем в меню Администрирование — Тестирование и исправление.
Настроим параметры тестирования следующим образом:
Важное примечание: Как показывает практика, для полного устранения некоторых логических дублей операцию тестирования и исправления требуется запустить повторно (до 3-4 раз подряд). С каждым проходом платформа глубже вычищает цепочки битых ссылок, которые и приводили к дублированию ключей в индексах.
Если ошибка возникает в таблице итогов (как в нашем примере с _AccumRegTotals4445), это означает, что повреждены именно рассчитанные агрегаты, в то время как сами движения документов могут быть абсолютно корректными. Мы можем полностью пересчитать итоги в режиме «1С:Предприятие»:
Этот процесс физически пересоздаст записи в таблицах итогов на основе детальных движений документов, устранив любые накопившиеся дубли.
Если мы локализовали проблемный объект (например, регистр накопления ТоварыНаСкладах) и знаем, что дублируются пустые значения (состоящие из нулевых GUID) на определенную дату (например, 01.01.2001), мы можем найти эти записи встроенным языком запросов 1С.
Откроем консоль запросов и выполним поиск записей с пустыми измерениями:
ВЫБРАТЬ
ТоварыНаСкладахИтоги.Период,
ТоварыНаСкладахИтоги.Номенклатура,
ТоварыНаСкладахИтоги.Склад,
ТоварыНаСкладахИтоги.ВНаличии
ИЗ
РегистрНакопления.ТоварыНаСкладах.Итоги КАК ТоварыНаСкладахИтоги
ГДЕ
ТоварыНаСкладахИтоги.Период = ДАТАВРЕМЯ(2001, 1, 1)
И ТоварыНаСкладахИтоги.Номенклатура = ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
И ТоварыНаСкладахИтоги.Склад = ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
Если запрос возвращает строки, это подтверждает наличие дублей. Для удаления таких записей напишем небольшую программную обработку, которая очистит пустой набор записей по заданным измерениям:
НаборЗаписей = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Период.Установить(Дата("20010101"));
НаборЗаписей.Отбор.Склад.Установить(Справочники.Склады.ПустаяСсылка());
НаборЗаписей.Отбор.Номенклатура.Установить(Справочники.Номенклатура.ПустаяСсылка());
// Записываем пустой набор с флагом замещения, тем самым удаляя битые итоги
НаборЗаписей.Записать(Истина);
Сообщить("Битые записи успешно удалены из базы данных!");
В ситуациях, когда база данных уже частично развернута в SQL, или у вас нет возможности полноценно работать с файловым вариантом, решить проблему дубликатов можно непосредственно средствами MS SQL Server.
Чтобы оперативно выявить строки, мешающие построению уникального индекса, запустим SQL Server Management Studio (SSMS), подключимся к нашей базе данных и выполним группировку по ключевым полям индекса:
SELECT COUNT(*) as Qty, _Period, _Fld4438RRef, _Fld4439RRef
FROM dbo._AccumRegTotals4445
GROUP BY _Period, _Fld4438RRef, _Fld4439RRef
HAVING COUNT(*) > 1;
Этот запрос мгновенно вернет нам конкретные строки, у которых количество упоминаний (поле Qty) больше единицы. Мы увидим проблемные измерения. Избавиться от лишней строки-дубля можно с помощью команды DELETE, ограничив ее системным идентификатором или точным набором полей:
WITH CTE AS (
SELECT *, ROW_NUMBER() OVER (
PARTITION BY _Period, _Fld4438RRef, _Fld4439RRef
ORDER BY (SELECT NULL)
) as RowNum
FROM dbo._AccumRegTotals4445
)
DELETE FROM CTE WHERE RowNum > 1;
Использование конструкции обобщенного табличного выражения (CTE) с оконной функцией ROW_NUMBER() позволяет безопасно удалить ровно одну строку из пары дубликатов, сохранив целостность данных.
Если ошибка уникальности блокирует загрузку или обновление метаданных базы, мы можем временно пересоздать индекс как неуникальный:
dbo._AccumRegTotals4445) и перейдем в ветку Индексы (Indexes)._AccumR4445_ByDims_TRRRRR и выберем Создать скрипт для... -> Удаление и создание в -> Новое окно редактора запросов.UNIQUE из конструкции CREATE UNIQUE CLUSTERED INDEX.DROP INDEX), а затем создания обычного индекса.Чтобы минимизировать риски возникновения подобных ошибок при последующих переносах баз или обновлениях конфигураций, придерживайтесь следующих правил:
.dt обязательно указывайте параметр Смещение дат = 2000. Исторически СУБД MS SQL Server не поддерживает даты ранее 1753 года. Если в файловой базе 1С присутствуют пустые даты (например, 01.01.0001), попытка записать их в SQL без смещения гарантированно приведет к критическому сбою. Смещение на 2000 лет вперед решает эту проблему на уровне платформы..dt для переноса выполняйте проверку конфигурации (меню Конфигурация — Проверка конфигурации) с включенными флагами «Проверка логической целостности конфигурации» и «Поиск некорректных ссылок». Это позволит обнаружить проблемы еще до этапа СУБД.dbo.Files (например, при вставке файлов настроек пользователей с расширением .pfl), вы можете безболезненно очистить эту таблицу в SQL-версии или полностью удалить кэш пользователей на сервере приложений 1С, поскольку данные в ней являются временными и пересоздаются автоматически.Применяя данные методики последовательно, вы сможете не только быстро восстановить работоспособность информационной базы 1С при переносе на SQL, но и существенно повысить общую стабильность и качество хранения ваших учетных данных.