При выполнении процедуры закрытия месяца, реструктуризации базы данных или операции Тестирование и исправление разработчики и администраторы 1С могут столкнуться со следующей критической ошибкой Microsoft SQL Server: Попытка вставки неуникального значения в уникальный индекс: Не удается вставить повторяющуюся строку ключа в объект "dbo._InfoRgSL..." с уникальным индексом "_InfoR..._ByDims_...". Часто эта проблема сопровождается аварийным завершением рабочих процессов кластера серверов 1С с сообщением о нехватке памяти.
Проанализируем природу этой ошибки, выясним назначение физических таблиц срезов и разберем по шагам надежные способы восстановления работоспособности базы данных.
В платформе 1С:Предприятие для периодических регистров сведений предусмотрена оптимизация быстродействия — хранение готовых срезов. В свойствах регистра на уровне метаданных доступны флаги Разрешить итоги: срез последних и Разрешить итоги: срез первых. При их включении в СУБД создаются отдельные физические таблицы:
_InfoRgSL<ID> (Slice Last) — физическая таблица для хранения актуального среза последних записей._InfoRgSF<ID> (Slice First) — физическая таблица для хранения среза первых записей.В этих таблицах платформа строит уникальный кластерный индекс по измерениям регистра (а также разделителям, если они используются). В идеальном состоянии на каждый уникальный набор ключевых измерений в таблице среза должна приходиться строго одна строка с максимальной датой периода.
Если в основной таблице регистра (_InfoRg...) по какой-либо причине (сбой транзакции, некорректная программная запись набором записей без контроля уникальности, ошибки старых релизов платформы) образовались дублирующие записи с одинаковым набором измерений и одинаковым значением периода, то при пересчете итогов или проведении документов платформа пытается поместить в таблицу _InfoRgSL две идентичные строки. СУБД блокирует такую операцию ошибкой нарушения уникальности индекса.
Чтобы точно сопоставить имя таблицы из ошибки SQL (например, _InfoRgSL16148) с конкретным объектом конфигурации 1С, выполним программное сопоставление через метод ПолучитьСтруктуруХраненияБазыДанных(). Напишем и выполним следующий фрагмент кода во внешней обработке:
СтруктураБД = ПолучитьСтруктуруХраненияБазыДанных();
Для Каждого СтрТаблицы Из СтруктураБД Цикл
Если Найти(СтрТаблицы.ИмяТаблицыХранения, "16148") > 0 Тогда
Сообщить("Имя метаданных: " + СтрТаблицы.Имя);
Сообщить("Назначение таблицы: " + СтрТаблицы.Назначение);
Сообщить("Имя в СУБД: " + СтрТаблицы.ИмяТаблицыХранения);
КонецЕсли;
КонецЦикла;
Это позволит однозначно убедиться, какому регистру сведений принадлежит сбойная таблица среза (в типовых конфигурациях чаще всего это регистры ЦеныНоменклатуры, КурсыВалют или ФИОФизЛиц).
Самый безопасный и быстрый способ устранить коллизию в таблицах _InfoRgSL без ручного вмешательства в структуру СУБД — сбросить признак хранения итогов среза:
РегистрыСведений.ЦеныНоменклатуры)._InfoRgSL и ее уникальные индексы из СУБД.Если сброс итогов не решает проблему из-за наличия логических дублей в теле самого регистра сведений, найдем некорректные записи с помощью запроса к основной таблице регистра. Разберем пример запроса для регистра ЦеныНоменклатуры:
ВЫБРАТЬ
Цены.Период КАК Период,
Цены.Номенклатура КАК Номенклатура,
Цены.ВидЦены КАК ВидЦены,
Цены.Характеристика КАК Характеристика,
КОЛИЧЕСТВО(*) КАК КоличествоДублей
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК Цены
СГРУППИРОВАТЬ ПО
Цены.Период,
Цены.Номенклатура,
Цены.ВидЦены,
Цены.Характеристика
ИМЕЮЩИ
КОЛИЧЕСТВО(*) > 1
После выявления дублирующих наборов выполним перезапись набора записей регистра штатными средствами платформы. При перезаписи набора с отбором по измерениям и периоду платформа автоматически схлопнет или удалит физический дубль:
Набор = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
Набор.Отбор.Период.Установить(НайденныйПериод);
Набор.Отбор.Номенклатура.Установить(НайденнаяНоменклатура);
Набор.Отбор.ВидЦены.Установить(НайденныйВидЦены);
Набор.Прочитать();
// Оставляем только одну актуальную запись, лишние удаляем
Если Набор.Количество() > 1 Тогда
Пока Набор.Количество() > 1 Цикл
Набор.Удалить(Набор.Количество() - 1);
КонецЦикла;
Набор.Записать(Истина);
КонецЕсли;
Падение процесса rphost или толстого клиента с ошибкой нехватки памяти (Memory allocation failure) при пересчете итогов за длительный период (несколько лет) обусловлено следующими факторами:
rphost.exe (32-bit) ограничено 2–4 ГБ оперативной памяти. При тяжелых запросах пересчета итогов регистров за много лет процесс исчерпывает этот лимит и аварийно завершается. Решением является перевод кластера на 64-разрядный сервер 1С:Предприятия.0 (без ограничений), чтобы предотвратить принудительный перезапуск процессов сервером до завершения транзакции.srvinfo (файлы snccntx), а также удалим пользовательские каталоги из %LocalAppData%\1C\1cv8 и %AppData%\1C\1cv8.Комплексное применение этих шагов позволяет полностью устранить конфликт уникальности в таблицах срезов и успешно завершить регламентные процедуры пересчета итогов.