При переносе информационной базы 1С из файлового режима (файл .1CD) в клиент-серверный вариант под управлением Microsoft SQL Server через стандартную выгрузку и загрузку файла .dt нередко возникает критическая ошибка: «Попытка вставки неуникального значения в уникальный индекс» (The CREATE UNIQUE INDEX statement terminated because a duplicate key was found). Чаще всего сбой происходит на таблицах итогов (_AccRgT) или таблицах значений субконто регистра бухгалтерии (_AccRgED).
Разберем природу этой проблемы, выясним, почему файловая база работает без видимых сбоев, и подробно рассмотрим пошаговые методы устранения дублирующихся записей.
В файловой СУБД 1С контроль уникальности вторичных таблиц и индексов устроен менее строго, чем в реляционных промышленных СУБД. При аварийных завершениях сеансов, сетевых сбоях или работе с базами критического объема (свыше 10–15 ГБ) во внутренних таблицах могут оставаться скрытые дубли строк или фантомные записи от прерванных транзакций.
Механизм создания выгрузки .dt выполняет последовательную логическую сериализацию данных, не производя жесткой проверки уникальности записей. При последующей загрузке в MS SQL Server платформа сначала вставляет строки в созданные таблицы, а затем формирует уникальные индексы. Если в данных обнаруживаются одинаковые сочетания ключевых полей, SQL Server аварийно прерывает операцию с ошибкой создания индекса.
В тексте ошибки всегда указывается имя таблицы и индекса. Проанализируем два наиболее распространенных случая:
_AccRgT<n>): сбой возникает из-за расхождения и дублирования рассчитанных итогов. Быстрое решение для обхода этой ошибки перед выгрузкой — отключить итоги в исходной базе. Для этого в режиме «1С:Предприятие» через обработку «Управление итогами» необходимо отключить итоги по всем регистрам, выполнить выгрузку, загрузить базу в SQL Server и включить итоги заново с пересчетом._AccRgED<n>): создается для регистров бухгалтерии, поддерживающих субконто. В ней хранятся аналитические разрезы проводок. Отключение итогов на эту таблицу не влияет, так как она хранит детальные движения. Здесь требуется найти конкретные сбойные проводки и удалить дубли.Если процесс загрузки базы на SQL прервался, наиболее надежным путем является устранение повреждений в исходной файловой базе перед созданием повторного архива .dt.
Разберем по шагам, как выявить и очистить поврежденные данные:
_RecorderRRef). В большинстве случаев дублирование движений субконто порождают тяжелые регламентные документы, такие как Расчет себестоимости, проводящиеся с огромным количеством проводок.chdbfl.exe (находится в каталоге bin платформы 1С) с активным флагом «Исправлять обнаруженные ошибки». Это восстановит целостность файловых страниц.
ПроблемнаяСсылка = Документы.РасчетСебестоимостиВыпуска.НайтиПоНомеру("000000012", Дата("20141130"));
Набор = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(ПроблемнаяСсылка);
Набор.Записать(); // Запись пустого набора удаляет движения и связанные субконто
.dt, выполним загрузку в MS SQL Server и перепроведем очищенный документ в новой базе.Поскольку физическая вставка записей в таблицы завершается до момента построения индексов, базу можно исправить непосредственно на стороне сервера СУБД, не повторяя многочасовую выгрузку и загрузку 15 ГБ данных.
Разберем по шагам процесс исправления на стороне SQL Server:
_AccRgED1152), с группировкой по ключевым полям индекса:
SELECT [_Period]
,[_RecorderTRef]
,[_RecorderRRef]
,[_LineNo]
,[_Correspond]
,[_KindRRef]
,COUNT(*) AS [TotalDuplicates]
FROM [dbo].[_AccRgED1152]
GROUP BY [_Period]
,[_RecorderTRef]
,[_RecorderRRef]
,[_LineNo]
,[_Correspond]
,[_KindRRef]
HAVING COUNT(*) > 1;
ROW_NUMBER() удалим дублирующие строки, оставив по одной уникальной записи для каждой связки ключей:
WITH DuplicatesCTE AS (
SELECT
_Period, _RecorderTRef, _RecorderRRef, _LineNo, _Correspond, _KindRRef,
ROW_NUMBER() OVER (
PARTITION BY _Period, _RecorderTRef, _RecorderRRef, _LineNo, _Correspond, _KindRRef
ORDER BY (SELECT NULL)
) AS RowNum
FROM [dbo].[_AccRgED1152]
)
DELETE FROM DuplicatesCTE WHERE RowNum > 1;
CREATE UNIQUE CLUSTERED INDEX [_AccRgED1152_ByPeriod_TRNRN]
ON [dbo].[_AccRgED1152] (_Period, _RecorderTRef, _RecorderRRef, _LineNo, _Correspond, _KindRRef);
Вместо ручного выполнения SQL-команда создания индекса можно запустить Конфигуратор 1С и выполнить «Тестирование и исправление» с установленным единственным флагом «Реструктуризация таблиц информационной базы». Платформа проверит структуру и автоматически создаст все недостающие индексы.
После завершения процедур откроем базу в режиме «1С:Предприятие», выполним проверку движений затронутого регистратора и проконтролируем корректность бухгалтерских итогов с помощью стандартных отчетов (оборотно-сальдовая ведомость).