Как восстановить поврежденные индексы MS SQL в базе данных 1С при обнаружении дублей

Системный администратор 1С v8.3 (Обычные формы) 1С:Управление торговлей
← На главную

В процессе эксплуатации баз данных 1С на платформе MS SQL Server системные администраторы могут столкнуться с серьезной проблемой: повреждением индексов, которое не удается исправить стандартными средствами DBCC CHECKDB. Ситуация осложняется тем, что при попытке ручного пересоздания индексов или выполнения тестирования и исправления (ТиИ) система выдает ошибку 1505: «Выполнение инструкции CREATE UNIQUE INDEX прервано, поскольку обнаружен повторяющийся ключ». В данной статье мы подробно разберем, как выйти из этой ситуации, очистить таблицу от дублей и корректно вернуть индексы на место.

Проанализируем причину возникновения проблемы

Обычно индексы в 1С обеспечивают уникальность записей. Однако при аварийном завершении работы SQL Server, сбоях дисковой подсистемы или некорректном выполнении команд восстановления целостности, физическая связь между индексом и данными может нарушиться. Если индекс был удален или поврежден, СУБД перестает контролировать уникальность, и в таблицу могут попасть идентичные строки. Рассмотрим основные типы индексов, которые чаще всего фигурируют в ошибках регистров накопления 1С:

Если при попытке создания любого из этих индексов возникает ошибка 1505, это означает, что в таблице _AccumRg (регистр накопления) уже присутствуют дублирующиеся записи, которые физически не позволяют индексу стать уникальным.

Шаг 1. Подготовительные действия и поиск дублей

Прежде всего, крайне важно создать полную резервную копию базы данных. Любые манипуляции с таблицами на уровне SQL могут привести к необратимой потере данных. Выясним причину ошибки, определив, какие именно записи являются дублями. Проанализируем ситуацию на примере индекса по регистратору и номеру строки (_ByRecorder_RN). Нам необходимо сгруппировать данные по полям, входящим в этот индекс.

Выполним следующий SQL-запрос для поиска проблемных строк в таблице вашего регистра (используйте инструменты, чтобы узнать структуру хранения базы данных и заменить _AccumRg7934 на имя вашей таблицы):


SELECT _RecorderTRef, _RecorderRRef, _LineNo, COUNT(*) as CountDuplicates
FROM [dbo].[_AccumRg7934]
GROUP BY _RecorderTRef, _RecorderRRef, _LineNo
HAVING COUNT(*) > 1;

Этот запрос покажет нам комбинации регистратора и номера строки, которые встречаются более одного раза. Именно эти записи блокируют создание индекса.

Шаг 2. Очистка таблицы от дублей через временную таблицу

Разберем алгоритм очистки, предложенный опытными специалистами. Суть метода заключается в том, чтобы временно переместить дублирующиеся записи в отдельное место, удалить их из основной таблицы и вернуть только уникальные экземпляры.

  1. Сгенерируйте скрипт создания индексов. В SQL Server Management Studio (SSMS) нажмите правой кнопкой на таблицу регистра, выберите "Script Table as" -> "CREATE To" -> "New Query Editor Window". Это поможет вам сохранить структуру индексов для их последующего восстановления.
  2. Удалите проблемные индексы. Если они еще существуют, выполните DROP INDEX (для последующего обслуживания пригодится IndexOptimize). Сначала удаляйте некластерные индексы, а затем кластерный.
  3. Создайте временную таблицу и перенесите дубли. Создадим таблицу с такой же структурой, как у регистра, и поместим туда повторяющиеся записи.

Пример логики переноса данных для исправления:


-- 1. Создаем копию структуры во временную таблицу
SELECT TOP 0 * INTO _AccumRg7934_temp FROM _AccumRg7934;

-- 2. Переносим все записи, у которых есть дубли, во временную таблицу
INSERT INTO _AccumRg7934_temp
SELECT * FROM _AccumRg7934
WHERE _RecorderRRef IN (
    SELECT _RecorderRRef FROM _AccumRg7934
    GROUP BY _RecorderTRef, _RecorderRRef, _LineNo
    HAVING COUNT(*) > 1
);

-- 3. Удаляем эти записи из основной таблицы
DELETE FROM _AccumRg7934
WHERE _RecorderRRef IN (SELECT _RecorderRRef FROM _AccumRg7934_temp);

Шаг 3. Восстановление уникальности и возврат данных

Теперь, когда основная таблица не содержит дублей, мы можем восстановить индексы. Выполните скрипты CREATE UNIQUE CLUSTERED INDEX и CREATE UNIQUE INDEX, которые вы сохранили на предыдущем шаге. После того как индексы успешно созданы, нам нужно вернуть данные из временной таблицы _AccumRg7934_temp, но уже без дублей.

Рассмотрим, как это сделать:


-- Вставляем обратно только уникальные записи (по одной для каждого набора ключей)
INSERT INTO _AccumRg7934
SELECT DISTINCT * FROM _AccumRg7934_temp;

-- После успешного переноса временную таблицу можно удалить
DROP TABLE _AccumRg7934_temp;

Важный момент: использование SELECT DISTINCT * поможет, если записи идентичны полностью. Если же записи различаются в полях ресурсов (например, разное количество или сумма), вам пригодится универсальная работа с регистрами, чтобы вручную решить, какую из записей оставить, либо просуммировать их значения, чтобы не «потерять» остатки в регистре.

Шаг 4. Использование средств Конфигуратора 1С

Если вы опасаетесь работать напрямую с SQL-запросами, можно попробовать решить проблему через Конфигуратор 1С, хотя этот метод не всегда срабатывает при наличии физических дублей в SQL. Посмотрим на альтернативные варианты:

Радикальный метод: Очистка и перепроведение

Проанализируем ситуацию, когда данных в регистре очень много, а повреждения обширны. Если проблемный регистр — это регистр накопления (например, «Товары на складах»), данные в нем являются производными от документов. В крайнем случае можно прибегнуть к полной очистке таблицы:

TRUNCATE TABLE _AccumRg7934;

После этой команды таблица станет пустой, индексы создадутся мгновенно и без ошибок. Затем в 1С необходимо будет запустить процедуру «Проведение документов» за весь период или воспользоваться обработкой «Управление итогами» для пересчета итогов, если повреждена была таблица итогов (_AccumRgT), а не движений. Это гарантированно восстановит целостность базы, хотя и потребует значительного времени на выполнение.

Заключение

Мы рассмотрели сложную техническую задачу по восстановлению структуры базы данных после сбоя. Помните, что появление дублей в уникальных индексах — это всегда следствие серьезного сбоя. Регулярная проверка базы данных командой DBCC CHECKDB и наличие актуальных бэкапов — лучшие средства защиты ваших нервов и данных пользователей.

← На главную