При работе с крупными базами данных "1С:Предприятие", особенно в конфигурации "Бухгалтерия предприятия 3.0", администраторы и разработчики иногда сталкиваются с критической ошибкой SQL-сервера: Cannot insert duplicate key row in object 'dbo._AccRgAT...' with unique index ..._by_Period. Эта ошибка возникает при попытке проведения документов (например, "Ввода остатков") или при выполнении регламентного пересчета итогов. В этой статье мы подробно разберем, почему возникают такие ситуации, как устроена структура таблиц регистра бухгалтерии и как безопасно восстановить работоспособность базы.
Прежде чем приступать к радикальным мерам в SQL Management Studio (SSMS), нам необходимо четко понимать архитектуру хранения данных регистра бухгалтерии. Платформа 1С разделяет данные на первичные (движения) и производные (итоги). Проанализируем основные типы таблиц:
_AccRg<n>) — здесь хранятся все проводки. Это "сердце" регистра. Если вы очистите эту таблицу, данные о хозяйственных операциях будут безвозвратно утеряны._AccRgED<n>) — вспомогательная таблица для хранения аналитических разрезов. Ее также нельзя трогать._AccRgAT<n>, _AccRgCT<n>, _AccRgT<n>) — это агрегированные данные, которые система рассчитывает для ускорения построения отчетов. Буква A в названии обычно означает итоги по счету, C — обороты между счетами, а T — общие итоги.Важный вывод: Таблицы итогов являются вторичными. Это означает, что их можно полностью очистить, и платформа 1С способна восстановить их содержимое "с нуля", опираясь на данные из основной таблицы движений. Поэтому ответ на вопрос автора — да, таблицы итогов удалять (очищать) можно, если штатные средства исправления не помогают.
Ошибка Cannot insert duplicate key row означает, что в индексной таблице SQL уже существует запись с набором ключевых полей (Период, Счет, Организация и т.д.), который система пытается вставить повторно. Рассмотрим основные причины возникновения "фантомных" записей:
_Splitter (Разделитель итогов). Если этот режим включен, система может создавать несколько строк для одной комбинации измерений. Сбои в логике схлопывания этих разделителей часто приводят к нарушению уникальности индекса.Прежде чем использовать SQL-скрипты, попробуем решить проблему программно. Рассмотрим метод, который инициирует удаление таблиц итогов на уровне платформы. Это наиболее корректный способ, так как 1С сама управляет структурой базы данных.
Выполним следующий фрагмент кода во внешней обработке:
// Отключаем использование итогов для регистра.
// Платформа сама выполнит очистку (Truncate/Drop) соответствующих таблиц итогов.
РегистрыБухгалтерии.Хозрасчетный.УстановитьИспользованиеИтогов(Ложь);
// Включаем использование итогов обратно.
// Платформа создаст пустые структуры таблиц и подготовит их к заполнению.
РегистрыБухгалтерии.Хозрасчетный.УстановитьИспользованиеИтогов(Истина);
// После этого необходимо запустить полный пересчет итогов
Этот метод часто оказывается эффективнее, чем просто "Тестирование и исправление" (ТиИ), так как жесткое отключение итогов гарантированно сносит текущие кэшированные данные.
Если программный метод не помог или выполняется слишком долго, воспользуемся средствами SQL. Для быстрой и полной очистки лучше всего подходит команда TRUNCATE. В отличие от DELETE, она не записывает удаление каждой строки в лог транзакций, выполняется мгновенно и сбрасывает счетчики.
Проанализируем скрипт для формирования команд очистки всех таблиц итогов:
-- Формируем команды очистки для регистров накопления
SELECT 'TRUNCATE TABLE ' + name + ';'
FROM sys.tables
WHERE name like '_AccumRgT%'
-- Формируем команды для итогов регистра бухгалтерии по счету
UNION
SELECT 'TRUNCATE TABLE ' + name + ';'
FROM sys.tables
WHERE name like '_AccRgAT%'
-- Формируем команды для оборотов между счетами
UNION
SELECT 'TRUNCATE TABLE ' + name + ';'
FROM sys.tables
WHERE name like '_AccRgCT%'
Пошаговый алгоритм действий:
TRUNCATE TABLE ... для проблемного регистра (номер регистра <n> можно узнать в консоли запросов или через параметры конфигурации).Как показал опыт автора темы, иногда помогает точечное удаление записей через DELETE. Рассмотрим ситуацию, когда ошибка возникает на конкретную дату. Если вы видите, что система ругается на дубль от 01.01.2015, а после удаления — на 01.02.2015, это явный признак "записей из будущего" или системного мусора.
Проанализируем пример команды выборочного удаления:
DELETE FROM _AccRgAT2905
WHERE _Period = '2015-01-01 00:00:00'
AND _AccountRRef = <бинарный_код_счета>
AND _Fld<n> = <значение_организации>
Однако помните, что ручное удаление в SQL — это крайняя мера. Если дублей много, проще и надежнее использовать TRUNCATE для всей таблицы и выполнить полный пересчет.
После того как таблицы итогов были очищены и пересчитаны, необходимо выполнить еще одно важное действие — обновление статистики SQL-сервера. Поскольку таблицы были сначала полностью пустыми, а затем резко наполнились данными, оптимизатор запросов SQL может строить неэффективные планы, что приведет к замедлению работы базы.
Выполните в SSMS следующую команду:
UPDATE STATISTICS _AccRgAT2905; (замените имя таблицы на вашу)
Или обновите статистику для всей базы данных:
EXEC sp_updatestats;
Посмотрим, что мы узнали: ошибка дублирования ключей в итогах — это следствие рассинхронизации агрегатов и первичных данных. Исправить ее можно либо через временное отключение итогов в коде 1С (УстановитьИспользованиеИтогов(Ложь)), либо через прямую очистку SQL-таблиц с префиксом _AccRgAT. Главное помнить, что сами проводки при этом не страдают, а итоги всегда можно восстановить штатным пересчетом.