Как исправить ошибки MS SQL и восстановить базу данных

Как исправить ошибки MS SQL и восстановить базу данных Полезное

Восстановление базы данных MS SQL Server — это возврат БД в согласованное рабочее состояние после сбоя: либо накатом резервной копии (RESTORE), либо ремонтом поврежденных страниц средствами DBCC CHECKDB (repair). Это два разных пути, и путать их нельзя: RESTORE возвращает данные без потерь до точки бэкапа, а repair в тяжелом режиме удаляет то, что не смог починить. Ниже — как отличить состояния БД, поставить диагноз через DBCC CHECKDB и выбрать безопасный путь; проверено на SQL Server 2019/2022, синтаксис актуален и для более ранних версий начиная с 2012.

Три термина, которые постоянно смешивают, разведем сразу:

  • recovery (восстановление согласованности) — фаза, которую движок сам проходит при старте БД: накат (redo) подтвержденных и откат (undo) незавершенных транзакций по журналу. Это не про резервные копии.
  • RESTORE (восстановление из резервной копии) — команда, которая перезаписывает БД содержимым файлов .bak/.trn. Основной и предпочтительный способ вернуть данные.
  • repair (ремонт) — опции DBCC CHECKDB (..., REPAIR_...), которые правят физические повреждения страниц. Крайняя мера, когда бэкапа нет.

Сначала — диагностика: в каком состоянии база

Не начинайте с ремонта. Сначала посмотрите состояние всех БД и модель восстановления — от этого зависит, доступен ли вам бэкап журнала.

SELECT name, state_desc, recovery_model_desc
FROM sys.databases
ORDER BY name;
-- state_desc: ONLINE, RESTORING, RECOVERY_PENDING, SUSPECT, EMERGENCY, OFFLINE

Что означают проблемные состояния и с чего начинать — в таблице. Важно: SUSPECT и RECOVERY_PENDING — разные диагнозы, и лечатся по-разному.

Состояние Вероятная причина Первое действие (не repair)
RECOVERY_PENDING Движок не смог даже начать recovery: нет файла журнала, нет места на диске, нет прав к файлу Устранить ресурсную причину (вернуть файл, освободить диск), затем ALTER DATABASE ... SET ONLINE
SUSPECT recovery началась, но не завершилась: поврежден или отсутствует журнал, сбой ввода-вывода Восстановить из резервной копии; если бэкапа нет — EMERGENCY + DBCC CHECKDB
RESTORING Цепочка RESTORE оставлена в состоянии NORECOVERY (это норма посреди восстановления) Догнать последним RESTORE ... WITH RECOVERY

RECOVERY_PENDING часто чинится без всякого ремонта данных — вернули потерянный файл журнала или освободили место, и база поднялась. Это упрощенная модель: в редких случаях за RECOVERY_PENDING стоит и физическое повреждение, тогда переходят к диагностике ниже.

DBCC CHECKDB: проверка целостности (безопасно)

DBCC CHECKDB без опций ремонта только читает и сообщает об ошибках — состояние БД он не меняет, запускать можно на рабочей базе (с учетом нагрузки).

DBCC CHECKDB (N'Sales') WITH NO_INFOMSGS, ALL_ERRORMSGS;
-- NO_INFOMSGS убирает информационный шум, ALL_ERRORMSGS показывает все найденные ошибки

В конце вывода CHECKDB печатает рекомендованный минимальный уровень ремонта, например: repair_allow_data_loss is the minimum repair level for the errors found by DBCC CHECKDB. Эта строка — подсказка, а не приказ немедленно запускать разрушающий ремонт: сначала оцените, есть ли резервная копия.

Уровни repair: чем отличаются

У ремонта два рабочих уровня. Оба требуют перевода БД в однопользовательский режим — иначе команда завершится ошибкой.

Уровень Что делает Потеря данных
REPAIR_REBUILD Чинит легкие повреждения: перестраивает некластерные индексы, правит ошибки, не затрагивающие данные Нет
REPAIR_ALLOW_DATA_LOSS Освобождает поврежденные страницы и пересобирает связи; исправляет тяжелые ошибки Да — удаленные страницы теряются вместе с данными

Устаревший REPAIR_FAST синтаксис принимает, но никаких действий он не выполняет — оставлен только для обратной совместимости, использовать его нет смысла.

REPAIR_REBUILD безопасен по данным, с него и начинают, если CHECKDB указал именно его:

-- Безопасный ремонт: без потери данных, но нужен монопольный доступ
ALTER DATABASE Sales SET SINGLE_USER WITH ROLLBACK IMMEDIATE;

DBCC CHECKDB (N'Sales', REPAIR_REBUILD) WITH NO_INFOMSGS, ALL_ERRORMSGS;

ALTER DATABASE Sales SET MULTI_USER;

WITH ROLLBACK IMMEDIATE откатывает чужие активные транзакции, чтобы получить монопольный доступ — это тоже изменение состояния, предупредите пользователей заранее.

RESTORE из бэкапа против repair: что выбирать

Правило простое: если есть годная резервная копия — восстанавливайте из нее, а не ремонтируйте. RESTORE возвращает данные без потерь до точки бэкапа; REPAIR_ALLOW_DATA_LOSS почти всегда что-то теряет. Ремонт с потерей данных — крайняя мера, когда бэкапа нет или он тоже поврежден.

Перед любым восстановлением при полной (FULL) или bulk-logged модели снимите резервную копию хвоста журнала (tail-log backup) — это последние записи, которых еще нет ни в одном бэкапе. Пропустите этот шаг — потеряете все транзакции с момента последней копии журнала.

-- Хвост журнала: последние незабэкапленные транзакции
BACKUP LOG Sales
TO DISK = N'D:\Backup\Sales_tail.trn'
WITH NORECOVERY;
-- Если файл ДАННЫХ поврежден, но сам журнал цел и обычный бэкап не проходит,
-- добавить NO_TRUNCATE (снимает хвост даже при недоступной БД):
-- WITH NORECOVERY, NO_TRUNCATE;
-- Если поврежден уже журнал и NO_TRUNCATE не проходит,
-- пробуют CONTINUE_AFTER_ERROR ВМЕСТО NO_TRUNCATE (бэкап уже ненадежен).

WITH NORECOVERY оставляет БД в состоянии восстановления, готовой принять накат копий. Дальше — полная копия, затем журналы по порядку, и последний файл с RECOVERY, который выводит базу в онлайн:

RESTORE DATABASE Sales
FROM DISK = N'D:\Backup\Sales_full.bak'
WITH NORECOVERY, REPLACE;

RESTORE LOG Sales
FROM DISK = N'D:\Backup\Sales_log.trn'
WITH NORECOVERY;

-- Последним накатываем хвост журнала и переводим БД в онлайн
RESTORE LOG Sales
FROM DISK = N'D:\Backup\Sales_tail.trn'
WITH RECOVERY;

Нужен откат к моменту до ошибочной операции — используйте восстановление на точку времени вместо RECOVERY на последнем шаге:

RESTORE LOG Sales
FROM DISK = N'D:\Backup\Sales_log.trn'
WITH STOPAT = N'2026-09-18T14:30:00', RECOVERY;

Точка во времени работает только при FULL или bulk-logged модели восстановления; при SIMPLE журнал не хранится и накат на произвольный момент недоступен.

EMERGENCY mode: последняя мера для SUSPECT без бэкапа

Если база помечена SUSPECT, обычной командой к ней не подключиться, а годной резервной копии нет — остается режим EMERGENCY. Он помечает БД как read-only и доступной только членам роли sysadmin: это дает шанс либо выгрузить уцелевшие данные, либо запустить ремонт.

Порядок ниже — разрушающий (REPAIR_ALLOW_DATA_LOSS может удалить данные), поэтому первый шаг — физическая копия файлов, а не команда:

-- ШАГ 0 (вне SQL): скопировать файлы .mdf и .ldf в отдельную папку.
--   Это единственный способ вернуться к исходному состоянию,
--   если ремонт удалит нужное. Не пропускать.

-- ШАГ 1: доступ к поврежденной БД и монопольный режим
ALTER DATABASE Sales SET EMERGENCY;
ALTER DATABASE Sales SET SINGLE_USER WITH ROLLBACK IMMEDIATE;

-- ШАГ 2: сначала оценить масштаб (без ремонта)
DBCC CHECKDB (N'Sales') WITH NO_INFOMSGS, ALL_ERRORMSGS;

-- ШАГ 3: ремонт как крайняя мера. ВНИМАНИЕ: удаляет поврежденные
--   страницы вместе с данными на них - потеря необратима.
DBCC CHECKDB (N'Sales', REPAIR_ALLOW_DATA_LOSS) WITH NO_INFOMSGS, ALL_ERRORMSGS;

-- ШАГ 4: вернуть базу пользователям
ALTER DATABASE Sales SET MULTI_USER;

После REPAIR_ALLOW_DATA_LOSS повторно запустите чистый DBCC CHECKDB и убедитесь, что ошибок больше нет. Проверьте бизнес-целостность вручную — ремонт чинит структуру страниц, но не знает про ваши правила: осиротевшие связи и пропавшие строки останутся на вашей совести.

Сторонние утилиты: когда штатных средств мало

Если файл .mdf поврежден настолько, что не подключается, а бэкапа нет, применяют коммерческие утилиты извлечения данных (например, класс инструментов «recovery toolbox для SQL Server»). Они читают сырой файл и выгружают то, что смогли распознать, в скрипт или новую БД. Относитесь к ним как к последнему рубежу после DBCC: работайте только с копией файла, а результат сверяйте с приложением. Точный набор поддерживаемых версий и повреждений зависит от конкретного продукта — это в «Точки для фактчека».

Выводы

  • Начинайте не с ремонта, а с диагностики: sys.databases для состояния и DBCC CHECKDB для целостности; SUSPECT и RECOVERY_PENDING лечатся по-разному.
  • RECOVERY_PENDING часто снимается устранением ресурсной причины (файл, место, права) и SET ONLINE, без правки данных.
  • RESTORE из бэкапа предпочтительнее ремонта: возвращает данные без потерь до точки копии. Перед восстановлением снимайте tail-log backup.
  • REPAIR_REBUILD чинит без потери данных; REPAIR_ALLOW_DATA_LOSS удаляет поврежденные страницы и применяется только при отсутствии бэкапа.
  • Разрушающий ремонт запускают в EMERGENCY + SINGLE_USER и всегда после копии файлов .mdf/.ldf; итог проверяют повторным CHECKDB.

Где применяется / связь с практикой

Освойте тему на практике

Диагностика состояний БД, планирование резервных копий и восстановление после сбоя — ежедневные задачи администратора и разработчика SQL Server. На практике важно не просто знать команды, а выстроить порядок: бэкап -> диагностика -> выбор между RESTORE и repair -> проверка результата. Разобрать это на реальных сценариях и стендах помогает курс MS SQL Server. Разработчик: там разбирают внутреннее устройство движка, журналирование и стратегии восстановления. Посмотреть формат и уровень подачи можно на открытых уроках Otus — они бесплатные.

Смежные темы: Особенности резервного копирования баз данных MS SQL, Привилегии в SQL.

FAQ

Можно ли запустить DBCC CHECKDB с REPAIR_REBUILD на рабочей базе без простоя?
Нет. Любой уровень ремонта требует однопользовательского режима (SET SINGLE_USER), то есть на время ремонта база недоступна остальным. Без ремонта, только для проверки, CHECKDB работает и на онлайн-базе.

Что делать, если tail-log backup не снимается из-за поврежденного файла данных?
Добавьте к BACKUP LOG ... WITH NORECOVERY опцию NO_TRUNCATE — она позволяет снять хвост журнала, даже когда основной файл данных недоступен или поврежден, при условии что сам файл журнала цел. Если поврежден уже журнал и NO_TRUNCATE не проходит, вместо нее пробуют CONTINUE_AFTER_ERROR, но такой бэкап уже считается ненадежным.

Почему после REPAIR_ALLOW_DATA_LOSS CHECKDB чистый, а данные все равно неверны?
Ремонт устраняет физические повреждения страниц, но не восстанавливает бизнес-логику: удаленные страницы уносят строки, а внешние ключи и ограничения при этом не пересчитываются. Поэтому после ремонта нужна ручная сверка целостности данных на уровне приложения.

OTUS Журнал