Ситуация, когда серверная база 1С перестает делать бэкапы, а стандартные средства SQL Server, такие как DBCC CHECKDB, зависают или аварийно завершаются, является критической. Если при этом в логах SQL Server появляется ошибка 1117 (Запрос не был выполнен из-за ошибки ввода/вывода на устройстве), это однозначно указывает на физическое повреждение поверхности жесткого диска или деградацию RAID-массива. В данной статье мы разберем по шагам, как действовать в такой ситуации, когда обычное копирование файла mdf невозможно, а сроки восстановления поджимают.
Прежде всего, проанализируем системные логи. Ошибка 1117 — это ответ операционной системы, который означает, что контроллер диска не смог прочитать данные из определенного сектора. Рассмотрим типичное сообщение из лога SQL Server:
A read of the file 'D:\SQL\DATA\buh_fok.mdf' at offset 0x00000362af6000 succeeded after failing 1 time(s) with error: 1117
Это сообщение говорит о том, что SQL Server столкнулся с «битым» блоком данных. Если DBCC CHECKDB с параметром REPAIR_ALLOW_DATA_LOSS прерывается или вызывает падение службы SQL, значит, повреждение затронуло критические системные таблицы базы данных или дерево метаданных. В таком состоянии стандартные механизмы восстановления SQL бессильны, так как они не могут даже прочитать структуру базы для ее исправления.
Поскольку оригинальный файл mdf заблокирован или не копируется обычными средствами Windows (процесс зависает на определенном проценте), нам необходимо создать его копию, игнорируя нечитаемые сектора. Никогда не проводите эксперименты над оригинальным поврежденным файлом!
Рассмотрим вариант использования специализированных утилит, которые умеют «пропускать» ошибки чтения, заполняя нечитаемые места нулями. Это позволит нам получить файл, который SQL Server сможет хотя бы «приаттачить» (подключить).
Ignore errors).dd, которая идеально подходит для таких задач:
# dd if=/dev/sda/path_to_base/baza.mdf of=/dev/sdb/copy_baza.mdf conv=sync,noerror bs=4k status=progress
Разберем параметры этой команды: noerror заставляет программу продолжать работу при ошибках чтения, а conv=sync заполняет нечитаемые блоки нулями, чтобы сохранить смещение (offset) всех последующих данных. Это критически важно для структуры mdf.
После того как вы получили «дырявую», но физически целостную копию файла на другом исправном диске, попробуем вернуть базу в рабочее состояние. Выясним, насколько серьезны потери. Подключите полученный файл к SQL Server.
Если база данных при подключении переходит в режим RECOVERY_PENDING или SUSPECT, переведите ее в аварийный режим и попробуйте выполнить восстановление:
ALTER DATABASE "myDBname" SET EMERGENCY;
GO
ALTER DATABASE "myDBname" SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO
DBCC CHECKDB ('myDBname', REPAIR_ALLOW_DATA_LOSS);
GO
ALTER DATABASE "myDBname" SET MULTI_USER;
GO
Важный момент: использование REPAIR_ALLOW_DATA_LOSS на исправном диске с копией файла пройдет гораздо быстрее и, скорее всего, не вызовет падения службы, так как физических ошибок чтения (1117) больше не будет. SQL Server просто удалит поврежденные страницы данных.
Если база данных подключилась, но CHECKDB все равно не справляется или 1С не запускается, проанализируем возможность ручного выгрузки данных. Часто повреждения приходятся на таблицы индексов или итогов, которые можно пересчитать, но иногда страдают и таблицы с документами.
Рассмотрим стратегию переноса данных в новую чистую базу той же конфигурации:
Пример запроса для переноса данных одной таблицы:
INSERT INTO NewDB.dbo._InfoRg1234 SELECT * FROM OldDB.dbo._InfoRg1234;
Проанализируем этот процесс: если при выполнении INSERT SQL Server выдает ошибку на конкретной таблице, значит, именно в ней находятся поврежденные данные. В этом случае мы можем попытаться выгрузить данные частями, обходя поврежденную страницу, используя фильтрацию по первичному ключу или другим полям.
Выясним, какая именно таблица 1С пострадала, используя данные из лога. В SQL Server размер страницы всегда равен 8 КБ (8192 байта). Возьмем offset из лога (например, 0x00000362af6000), переведем его в десятичный вид и разделим на 8192.
Зная номер страницы, мы можем выполнить команду:
DBCC PAGE ('имя_базы', 1, номер_страницы, 3);
В выводе этой команды в поле Metadata: ObjectId будет указан ID объекта. Выполнив запрос SELECT OBJECT_NAME(ID_объекта), мы узнаем имя таблицы 1С. Если это индекс (имя начинается с _DocumentL... или заканчивается на _idx), его можно просто пересоздать через консоль SQL или реиндексацию в конфигураторе 1С, что полностью решит проблему без потери данных.
Подводя итог, проанализируем последовательность действий при возникновении ошибки 1117:
dd или Unstoppable Copier.Помните, что после восстановления базы методом REPAIR_ALLOW_DATA_LOSS необходимо обязательно выполнить Тестирование и исправление (ТиИ) в конфигураторе 1С, так как SQL Server восстанавливает физическую целостность страниц, но может нарушить логические связи между таблицами 1С.