Представьте ситуацию: в самый разгар рабочего дня при обмене данными, проведении документов или расчете себестоимости в 1С:Предприятии возникает критическая ошибка СУБД: «Microsoft SQL Server Native Client 10.0: Страница (1:10034843) в базе данных с идентификатором 11 помечена RestorePending, что может означать повреждение диска». Попытка запустить стандартную проверку целостности или пересчет итогов приводит к тому, что база данных аварийно переходит в статус SUSPECT и полностью блокирует работу организации.
Что делать, если актуального бэкапа под рукой нет, база данных весит более 150 ГБ, а бизнес требует немедленного восстановления работоспособности систем? В этой статье мы подробно разберем природу возникновения ошибки RestorePending, проанализируем причины ее появления и предоставим пошаговый алгоритм аварийного спасения базы данных 1С.
Когда СУБД MS SQL Server при чтении или записи данных сталкивается с неустранимой физической ошибкой ввода-вывода (чаще всего это низкоуровневая ошибка СУБД 824), она изолирует сбойный участок. Страница данных размером 8 КБ помечается статусом RestorePending (ожидает восстановления). Это защитный механизм СУБД: SQL Server запрещает любые дальнейшие операции с этой страницей, чтобы предотвратить дальнейшее разрушение логической структуры файлов.
Информацию обо всех поврежденных страницах СУБД записывает в системную таблицу msdb.dbo.suspect_pages. Давайте проанализируем структуру полей этой таблицы, основываясь на данных из лога ошибки:
.mdf).Наличие ошибок с кодом event_type = 2 — классический признак деградации накопителя. Подобное часто случается на твердотельных дисках пользовательского сегмента (например, на контроллерах SandForce, как у SSD Kingston SVP200S3), где под высокой нагрузкой ввода-вывода СУБД начинают изнашиваться ячейки памяти, давать сбои алгоритмы аппаратной сборки мусора (Garbage Collection) или проявляется ошибка прошивки контроллера.
В попытке исправить ситуацию администраторы часто запускают тяжелые операции — например, пересчет итогов регистров в 1С. Это большая ошибка при наличии физических повреждений диска. Пересчет итогов инициирует лавинообразное чтение и запись в поврежденные таблицы. Когда SQL Server повторно натыкается на нечитаемые сектора и понимает, что не может гарантировать целостность транзакций (особенно если повреждены системные метаданные или цепочки страниц), он аварийно переводит базу в режим SUSPECT.
В этом состоянии база данных становится недоступной для 1С, и любые попытки подключения вызывают ошибку соединения.
Перед тем как приступать к любым активным манипуляциям в среде SQL Server, необходимо выполнить золотое правило системного администрирования — сделать резервную копию. Даже если база данных повреждена или находится в статусе SUSPECT, мы обязаны сохранить ее текущее состояние, чтобы не столкнуться с полной потерей данных в случае неудачного исправления.
Поскольку стандартные средства резервного копирования SQL Server могут выдать ошибку при чтении битых страниц, выполните следующие действия:
.mdf и .ldf) в безопасное место на другом физическом накопителе.Важная рекомендация: Если есть подозрение на аппаратный сбой жесткого диска или SSD (на что указывает ошибка RestorePending), настоятельно рекомендуется развернуть скопированные файлы базы данных на другом, заведомо исправном физическом сервере для проведения восстановительных работ.
Если у вас нет актуального чистого бэкапа, единственным способом реанимировать базу данных, застрявшую в режиме SUSPECT, является перевод ее в аварийный режим и принудительное исправление структуры файлов с помощью утилиты DBCC CHECKDB.
Рассмотрим по шагам этот процесс в SQL Server Management Studio (SSMS). Выполните следующий скрипт:
-- Шаг 2.1. Переводим базу данных в аварийный режим EMERGENCY
-- Это делает базу доступной администраторам только для чтения и отключает логирование
ALTER DATABASE [Имя_Вашей_Базы] SET EMERGENCY;
GO
-- Шаг 2.2. Переводим базу в монопольный режим работы SINGLE_USER
-- Параметр ROLLBACK IMMEDIATE принудительно разрывает все текущие сессии пользователей
ALTER DATABASE [Имя_Вашей_Базы] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO
-- Шаг 2.3. Запускаем процедуру исправления ошибок с возможной потерей данных
-- Параметр REPAIR_ALLOW_DATA_LOSS физически удалит поврежденные страницы данных
-- для восстановления логической и физической целостности файлов СУБД.
DBCC CHECKDB ([Имя_Вашей_Базы], REPAIR_ALLOW_DATA_LOSS) WITH ALL_ERRORMSGS, NO_INFOMSGS;
GO
-- Шаг 2.4. Возвращаем базу данных в многопользовательский режим MULTI_USER
ALTER DATABASE [Имя_Вашей_Базы] SET MULTI_USER;
GO
Обратите внимание: параметр REPAIR_ALLOW_DATA_LOSS — это крайняя мера. Он физически вырезает из файлов базы данных те 8-килобайтные страницы, на которых контрольная сумма оказалась неверной. Вместе со страницами безвозвратно удаляются и данные, которые на них хранились. Однако в контексте архитектуры 1С:Предприятия у нас есть важное преимущество, о котором мы поговорим ниже.
В архитектуре баз данных 1С:Предприятия существует четкое разделение таблиц регистров на две основные категории:
_AccumRg14497) — содержат первичные записи документов (регистраторы, периоды, измерения, ресурсы). Это те данные, которые пользователи вводят вручную. Их терять нельзя._AccumRgT14497 — обратите внимание на букву «T» в названии) — содержат предварительно рассчитанные агрегированные остатки на начало каждого месяца. Эти таблицы нужны исключительно для ускорения работы отчетов и проведения документов «задним числом».Если поврежденные страницы (как в примере автора: 10034843, 10034845, 10034856) относятся исключительно к таблице итогов (_AccumRgT...), то физическое удаление этих страниц утилитой DBCC CHECKDB с ключом REPAIR_ALLOW_DATA_LOSS абсолютно безопасно для бизнеса. Сами первичные движения документов останутся нетронутыми в таблицах движений, а разрушенные итоги мы сможем легко пересчитать и восстановить стандартными средствами платформы 1С.
Чтобы точно определить, за какой регистр отвечает поврежденная таблица, запустите в конфигураторе 1С или во внешней обработке следующий код на встроенном языке 1С:
// Выясняем имя регистра по имени таблицы в СУБД
СтруктураБазы = ПолучитьСтруктуруХраненияБазыДанных();
Для Каждого СтрокаТаблицы Из СтруктураБазы Цикл
Если СтрокаТаблицы.ИмяТаблицыХранения = "_AccumRgT14497" Тогда
Сообщить("Поврежденная таблица принадлежит объекту метаданных: " + СтрокаТаблицы.ИмяТаблицы);
КонецЕсли;
КонецЦикла;
Попытка запустить пересчет итогов через Конфигуратор 1С («Тестирование и исправление» -> «Пересчет итогов») на огромной базе данных в 160 ГБ может выполняться сутками, особенно если дисковая подсистема работает медленно или изношена. Платформа 1С будет пытаться последовательно обновлять и перезаписывать существующие записи, спотыкаясь о разрушенные структуры.
Гораздо более эффективным и быстрым способом является полная очистка таблиц итогов на уровне СУБД с помощью команды TRUNCATE TABLE, с последующим быстрым расчетом итогов с «чистого листа» в 1С. Операция TRUNCATE TABLE выполняется мгновенно, так как она не удаляет строки по одной, а просто освобождает страницы данных на уровне файловой системы СУБД.
Внимание: СУБД может заблокировать выполнение команды TRUNCATE TABLE, если страница таблицы уже помечена как RestorePending, поскольку для удаления структуры серверу необходимо прочитать системные карты распределения страниц (IAM). В этом случае сначала обязательно выполните Шаг 2 (ремонт базы через REPAIR_ALLOW_DATA_LOSS), и только после этого приступайте к очистке.
Рассмотрим SQL-скрипт, который автоматически формирует команды очистки для всех таблиц итогов регистров накопления, бухгалтерии и таблиц регистрации изменений (это значительно ускорит процесс реанимации):
-- Генерация команд очистки (TRUNCATE) таблиц итогов регистров накопления
SELECT 'TRUNCATE TABLE ' + name + ';' AS [Команда_Очистки]
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%'
UNION
-- Генерация команд для таблиц регистрации изменений (планы обмена)
SELECT 'TRUNCATE TABLE ' + name + ';'
FROM sys.tables
WHERE name LIKE '%ChngR%';
Скопируйте результат выполнения этого запроса, вставьте в новое окно запроса SSMS и запустите выполнение. Все таблицы итогов очистятся мгновенно. База данных физически станет «легче», а все логические нестыковки в остатках будут устранены.
После успешной очистки таблиц итогов на уровне SQL-сервера, база данных 1С запустится без ошибок, однако во всех отчетах остатки будут нулевыми. Не пугайтесь — это логично, ведь мы очистили таблицы агрегатов. Теперь нам необходимо запустить пересчет итогов, чтобы платформа 1С заново рассчитала остатки на основе первичных документов.
Выполните следующие шаги:
Поскольку таблицы итогов были предварительно очищены на уровне СУБД, пересчет займет в разы меньше времени, так как системе не придется выполнять ресурсоемкие операции сверки и удаления старых записей — она просто запишет новые чистые данные.
Рассмотрим альтернативный сценарий. Что делать, если у вас был настроен регулярный бэкап и база данных работает в модели восстановления FULL (полная) или BULK_LOGGED (с неполным протоколированием)? В этом случае вам не нужно восстанавливать всю базу данных объемом 160 ГБ из резервной копии, теряя драгоценные часы работы пользователей.
MS SQL Server поддерживает технологию точечного восстановления отдельных поврежденных страниц буквально «на лету» без отключения остальных пользователей от системы. Проанализируем, как это сделать по шагам:
Запустите восстановление только конкретных поврежденных страниц (взятых из таблицы suspect_pages) из последнего файла полной резервной копии:
RESTORE DATABASE [Имя_Вашей_Базы]
PAGE = '1:10034843, 1:10034845, 1:10034856'
FROM DISK = 'D:\Backups\Full_Backup.bak'
WITH NORECOVERY;
GO
Сделайте бэкап активной части журнала транзакций (Tail-Log Backup) поврежденной базы данных, чтобы сохранить самые последние изменения, сделанные пользователями с момента последнего бэкапа:
BACKUP LOG [Имя_Вашей_Базы]
TO DISK = 'D:\Backups\TailLog.trn'
WITH NO_TRUNCATE, NORECOVERY;
GO
Накатите последовательно все бэкапы журналов транзакций, созданные после полного бэкапа (если они есть), используя параметр WITH NORECOVERY.
Накатите финальный бэкап хвоста журнала транзакций и верните базу данных в оперативный режим:
RESTORE LOG [Имя_Вашей_Базы]
FROM DISK = 'D:\Backups\TailLog.trn'
WITH RECOVERY;
GO
После выполнения этих команд SQL Server точечно заменит поврежденные страницы здоровыми копиями из бэкапа и «докрутит» транзакции до самого последнего актуального состояния. Ошибка RestorePending исчезнет, а база данных вернется к полноценной работе за считанные минуты.