При переносе базы данных 1С из файлового режима в клиент-серверный на СУБД PostgreSQL администраторы и разработчики часто сталкиваются со следующей критической ошибкой:
«Ошибка загрузки информационной базы. В информационную базу загружены не все данные по причине: Нарушено условие уникальности данных. Попытка вставки неуникального значения в уникальный индекс: ERROR: could not create unique index...»
В этой статье мы подробно разберем, почему возникает данная проблема, как локализовать поврежденную таблицу с помощью встроенных инструментов 1С и как программно устранить дублирование данных в файловой копии перед успешной миграцией на сервер.
Это классический парадокс платформы 1С. Файловая база данных (формат .1cd) использует собственный встроенный движок СУБД. Настройки контроля уникальности и записи данных в файловой СУБД в ряде режимов (например, при обмене данными с установленным свойством ОбменДанными.Загрузка = Истина) могут быть лояльны к некоторым несоответствиям структуры. В результате в таблице физически могут появиться записи с одинаковыми ключевыми полями индекса.
При этом стандартное «Тестирование и исправление» (ТИИ) и утилита проверки целостности chdbfl.exe часто рапортуют о том, что база абсолютно здорова. Проблема «всплывает» только при попытке переезда на клиент-серверную архитектуру:
.dt платформа 1С последовательно создает таблицы в базе данных PostgreSQL и загружает в них «сырые» данные.CREATE UNIQUE INDEX).Выясним причину этой проблемы и рассмотрим по шагам, как найти и исправить поврежденные данные.
Проанализируем текст ошибки, с которой столкнулся пользователь:
ERROR: could not create unique index "_reference323_4" DETAIL: Key (_fld1080, _code, _idrref)=(0, 000000004, \x8f4f20cf30e2c00a11eacc7c9724c348) is duplicated.
Из этого сообщения мы можем извлечь следующие технические сведения:
_reference323. Префикс _reference указывает на то, что это таблица справочника._fld1080 (разделитель данных или область данных, если используется разделение), _code (код элемента справочника) и _idrref (внутренний уникальный идентификатор GUID).Чтобы понять, какому именно справочнику в конфигураторе соответствует таблица _reference323, нам потребуется запустить файловую базу в режиме «1С:Предприятие» и воспользоваться встроенным методом платформы ПолучитьСтруктуруХраненияБазыДанных(). Для этой задачи можно использовать обработку для анализа структуры хранения базы данных.
Для этого создадим простую внешнюю обработку и выполним следующий код в модуле:
ТаблицаСтруктуры = ПолучитьСтруктуруХраненияБазыДанных();
Для Каждого СтрокаТаблицы Из ТаблицаСтруктуры Цикл
Если ВРег(СтрокаТаблицы.ИмяТаблицыХранения) = "_REFERENCE323" Тогда
Сообщить("Имя объекта в конфигурации: " + СтрокаТаблицы.ИмяТаблицы);
Прервать;
КонецЕсли;
КонецЦикла;
В результате выполнения этого кода мы получим точное представление о проблемном объекте. В рассматриваемом примере этим объектом оказался справочник Справочник.ВидыОбъектовЕГАИС.
Разберем подробнее, почему в справочнике ВидыОбъектовЕГАИС (или аналогичных системных справочниках ГИСМ, ВетИС, классификаторах банков и валют) появляются дубли. Чаще всего это происходит по следующим причинам:
При визуальном осмотре справочника в режиме «1С:Предприятие» вы увидите два или более элемента с одинаковыми наименованиями и кодами, помеченными как предопределенные (со значком «желтого шарика» на иконке).
Чтобы убедиться в наличии дублирующихся записей, напишем и выполним в консоли запросов следующий SQL-ориентированный запрос. Он находит элементы, у которых заполнено внутреннее свойство ИмяПредопределенныхДанных, и выводит только те имена, которые встречаются более одного раза:
ВЫБРАТЬ
ЕГАИС.ИмяПредопределенныхДанных КАК ИмяПредопределенныхДанных,
КОЛИЧЕСТВО(ЕГАИС.Ссылка) КАК КоличествоДублей
ИЗ
Справочник.ВидыОбъектовЕГАИС КАК ЕГАИС
ГДЕ
ЕГАИС.ИмяПредопределенныхДанных <> ""
СГРУППИРОВАТЬ ПО
ЕГАИС.ИмяПредопределенныхДанных
ИМЕЮЩИЕ
КОЛИЧЕСТВО(ЕГАИС.Ссылка) > 1
Проанализируем ситуацию: если запрос вернул строки, значит, в базе действительно присутствуют физические дубли предопределенных данных, которые блокируют создание уникального индекса СУБД.
Попытка удалить предопределенный элемент справочника вручную через интерфейс пользователя 1С или стандартной обработкой удаления объектов завершится неудачей — платформа заблокирует это действие, так как элемент связан с метаданными конфигурации.
Чтобы решить эту задачу, нам необходимо программно «отвязать» дублирующиеся элементы от метаданных конфигуратора, превратив их в обычные элементы справочника. Для этого выполним следующий алгоритм в файловой копии базы данных:
// Шаг 4.1. Находим дубликаты предопределенных элементов
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЕГАИС.Ссылка КАК Ссылка,
| ЕГАИС.ИмяПредопределенныхДанных КАК ИмяПредопределенныхДанных
|ИЗ
| Справочник.ВидыОбъектовЕГАИС КАК ЕГАИС
|ГДЕ
| ЕГАИС.ИмяПредопределенныхДанных В
| (ВЫБРАТЬ
| ВТ.ИмяПредопределенныхДанных
| ИЗ
| Справочник.ВидыОбъектовЕГАИС КАК ВТ
| ГДЕ
| ВТ.ИмяПредопределенныхДанных <> """"
| СГРУППИРОВАТЬ ПО
| ВТ.ИмяПредопределенныхДанных
| ИМЕЮЩИЕ
| КОЛИЧЕСТВО(ВТ.Ссылка) > 1)";
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
// Используем соответствие для сохранения первого "правильного" элемента
// и очистки последующих дубликатов
ОбработанныеИмена = Новый Соответствие;
Пока Выборка.Следующий() Цикл
ИмяПредопределенного = Выборка.ИмяПредопределенныхДанных;
Если ОбработанныеИмена[ИмяПредопределенного] = Неопределено Тогда
// Это первый встреченный элемент, его мы оставляем как основной
ОбработанныеИмена.Вставить(ИмяПредопределенного, Выборка.Ссылка);
Сообщить("Оставляем как основной: " + Выборка.Ссылка + " (" + ИмяПредопределенного + ")");
Иначе
// Это дубликат. Снимаем признак предопределенности
ОбъектДубль = Выборка.Ссылка.ПолучитьОбъект();
ОбъектДубль.ИмяПредопределенныхДанных = "";
Попытка
ОбъектДубль.Записать();
Сообщить("Успешно 'отвязан' от метаданных дубликат: " + Выборка.Ссылка);
Исключение
Сообщить("Не удалось перезаписать объект: " + ОписаниеОшибки());
КонецПопытки;
EndЕсли;
КонецЦикла;
КонецЕсли;
После выполнения этого кода лишние дублирующие элементы потеряют статус предопределенных (иконка «шарика» исчезнет) и превратятся в обычные элементы справочника, которые система позволит нам удалить.
После того как дубликаты стали обычными элементами, мы не можем просто так удалить их из базы, так как на них могут ссылаться существующие документы или регистры сведений (например, документы ЕГАИС).
Для корректного завершения процедуры выполним следующие действия:
Виды объектов ЕГАИС.Наименование или Код.После успешного слияния дубликатов выполним завершающие регламентные операции в файловой базе. Для автоматизации регламентного обслуживания и резервного копирования нескольких информационных баз можно использовать автоматическое архивирование и тестирование баз в Обновляторе 1С.
.dt..dt.Поскольку все дубликаты записей по уникальным ключевым полям были успешно удалены в файловой копии, СУБД PostgreSQL без ошибок выполнит SQL-запрос CREATE UNIQUE INDEX, и загрузка завершится успешно.