Восстановление баз данных Microsoft SQL Server. Восстановление базы данных

Одним из основных требований к СУБД является надежность хранения данных во внешней памяти. Под надежностью хранения понимается то, что СУБД должна быть в состоянии восстановить последнее согласованное состояние БД после любого аппаратного или программного сбоя. Обычно рассматриваются два возможных вида аппаратных сбоев: так называемые мягкие сбои, которые можно трактовать как внезапную остановку работы компьютера (например, аварийное выключение питания), и жесткие сбои, характеризуемые потерей информации на носителях внешней памяти. Примерами программных сбоев могут быть: аварийное завершение работы СУБД (по причине ошибки в программе или в результате некоторого аппаратного сбоя) или аварийное завершение пользовательской программы, в результате чего некоторая транзакция остается незавершенной. Первую ситуацию можно рассматривать как особый вид мягкого аппаратного сбоя; при возникновении последней требуется ликвидировать последствия только одной транзакции.

В любом случае для восстановления БД нужно располагать некоторой дополнительной информацией. Другими словами, поддержание надежности хранения данных в БД требует избыточности хранения данных, причем та часть данных, которая используется для восстановления, должна храниться особо надежно. Наиболее распространенным методом поддержания такой избыточной информации является ведение журнала изменений БД.

Журнал - это особая часть БД, недоступная пользователям СУБД и поддерживаемая с особой тщательностью (иногда поддерживаются две копии журнала, располагаемые на разных физических дисках), в которую поступают записи обо всех изменениях основной части БД. При ведении журнала придерживаются стратегии "упреждающей" записи, которая заключается в том, что запись об изменении любого объекта БД должна попасть во внешнюю память журнала раньше, чем измененный объект попадет во внешнюю память основной части БД. Известно, что если в СУБД корректно соблюдается данное условие, то с помощью журнала можно решить все проблемы восстановления БД после любого сбоя.

При мягком сбое во внешней памяти основной части БД могут находиться объекты, модифицированные транзакциями, не закончившимися к моменту сбоя, и могут отсутствовать объекты, модифицированные транзакциями, которые к моменту сбоя успешно завершились но не были записаны во внешнюю память. Целью процесса восстановления после мягкого сбоя является состояние внешней памяти основной части БД, которое возникло бы при фиксации во внешней памяти изменений всех завершившихся транзакций и которое не содержало бы никаких следов незаконченных транзакций. Для того, чтобы этого добиться, сначала производят откат незавершенных транзакций, а потом повторно воспроизводят те операции завершенных транзакций, результаты которых не отображены во внешней памяти. Для восстановления БД после жесткого сбоя используют журнал и архивную копию БД. Архивная копия - это полная копия БД к моменту начала заполнения журнала. Для нормального восстановления БД после жесткого сбоя необходимо, чтобы журнал не пропал. Тогда восстановление БД состоит в том, что, исходя из архивной копии, по журналу воспроизводится работа всех транзакций, которые закончились к моменту сбоя.

Хотя к ведению журнала предъявляются особые требования по части надежности, в принципе возможна и его утрата. Тогда единственным способом восстановления базы данных является возврат к архивной копии. Конечно, в этом случае не удастся получить последнее согласованное состояние базы данных, но это лучше, чем ничего.

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

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

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

Запомните, если Вы восстанавливаете базу, используя Simple Recovery Model, Вам нужно будет восстановить только последнюю полную копию. Если же Вы используете Full или Bulk Recovery Model , Вы должны восстановить полную копию, затем последнюю дифференциальную копию и все копии журналов транзакций. Изучим подробнее процессы восстановления.

Восстановление базы данных из полной копии.

Независимо от модели восстановления, первым шагом всегда является восстановление последней полной резервной копии. Для восстановления БД в Enterprise Manager, следует выделить базу данных, дважды щелкнуть по ней правой кнопкой мыши и выбрать в контекстном меню “All Tasks > Restore Database”, после этого откроется диалоговое окно, показанное на Рисунке A.

Рисунок А.

Диалоговое окно Restore Database позволяет просматривать все последние резервные копии в хронологическом порядке. Там же Вы можете выбрать базу данных, которую нужно восстановить. На вкладке Options показанной на Рисунке B, Вы можете выбрать сделующие опции:

  • Eject tapes after restoring each backup (выгружать ленту после каждого восстановления)
  • Prompt befor restoring each backup (выдавать дополнительное предупреждение перед началом восстановления каждой копии)
  • Force restore over existing database (осуществлять восстановление поверх существующей базы данных), эта опция эквивалентна Move в T-SQL.

Рисунок B.

В нижней части окна находятся три переключателя, которые позволяют определить состояние базы после восстановления копии:

  • Leave Database Operational. No Additional Transaction Logs Can Be Restored.
    • Если Вы выбрали это значение, то после загрузки резервной копии будет инициирован процесс восстановления, что приведет к откату всех незавершенных транзакций. Станет невозможной загрузка дополнительных копий журнала транзакций. Пользователи получат возможность нормально работать с базой данных.
  • Leave Database Nonoperational But Able To Restore Additional Transaction Logs.
    • По окончании загрузки копии база данных будет оставаться временно недоступной. Будет необходимо загрузить дополнительные копии, после чего инициировать процесс восстановления.
  • Leave Database Read-Only And Able To Restore Additional Transaction Logs.
    • База данных становится доступной только для чтения. Вы можете загрузить дополнительные резервные копии журнала транзакций. Эта опция используется для создания резервного сервера (Standby Server)

Для восстановления базы данных и журналов транзакций осталось просто нажать кнопку OK.

Восстановление базы данных с помощью T-SQL.

Восстановление базы данных можно выполнить и с помощью T-SQL, который предлагает больше опций чем Enterprise Manager. Синтакс использования T-SQL команды следующий:

    RESTORE DATABASE { database_name | @ database_name_var }
    [ FROM < backup_device > [ , ...n ] ]
    [ WITH
    [ RESTRICTED_USER ]
    [ [ , ] FILE = { file_number | @ file_number } ]
    [ [ , ] PASSWORD= { password | @ password_variable } ]
    [ [ , ] MEDIANAME= { media_name | @ media_name_variable } ]
    [ [ , ] MEDIAPASSWORD= { mediapassword | @ mediapassword_variable } ]
    [ [ , ] MOVE " logical_file_name " TO " operating_system_file_name " ]
    [ , ...n ]
    [ [ , ] KEEP_REPLICATION ]
    [ [ , ] { NORECOVERY | RECOVERY | STANDBY = undo_file_name } ]
    [ [ , ] { NOREWIND | REWIND } ]
    [ [ , ] { NOUNLOAD | UNLOAD } ]
    [ [ , ] REPLACE ]
    [ [ , ] RESTART ]
    [ [ , ] STATS [ = percentage ] ]

Для детального изучения каждой опции следует прочитать описание в SQL Server 2000 Books Online .

На Рисунке C показано восстановление базы данных Pubs из полной копии с устройства резервного копирования.

Рисунок С.

Восстановление базы данных из дифференциальной копии.

Если Вы используете Full или Bulk Recovery Model, Вы должны выполнить сначала восстановление полной резервной копии, затем последней дифференциальной копии и всех журналов транзакций. Для выполнения восстановления базы данных, используя дифференциальную копию, в Enterprise Manager необходимо выделить базу данных, дважды щелкнуть по ней правой кнопкой мыши и выбрать в контекстном меню “All Tasks > Restore Database”, выбрать восстановления полной и дифференциальной копии базы данных, а затем нажать OK. (исунок D)

Рисунок D.

Синтаксис команды Restore для выполнения восстановления с использованием дифференциальных копий, показан на Рисунке Е.

Рисунок Е.

Восстановление журнала транзакций.

Перед началом восстановления журнала транзакций, Вы должны восстановить полную и последнюю дифференциальную копию базы. Затем Вы можете восстанавливать журналы транзакций в соответсвующем порядке. Если Вы используете Enterprise Manager, нужно выделить базу данных, дважды щелкнуть по ней правой кнопкой мыши и выбрать в контекстном меню “All Tasks > Restore Database”, выбрать все нужные копии и, если есть необходимость, опцию Point in Time Restore (восстановление на определенный момент времени) (Рисунок F).

Рисунок F.

Синтаксис команды Restore для восстановления журнала транзакций, показан на РисункеG.

Рисунок G.

Подведем итоги. Резервное копирование и восстановление базы данных – это одна из основных, наиболее важных задач администратора баз данных. В любой момент времени Вы должны быть уверены в своей способности восстановить базу данных SQL Server 2000 согласно Вашему плану аварийного восстановления. Если же у Вас нет плана аварийного восстановления, я рекомендую начать работать над ним. В случае, если что-то произойдет и данные будут потеряны, следующей потерей для Вас может стать потеря места работы.

Сегодня в уроке: MySQL. (MySQL - система свободного управления базами данных). Восстановить базу данных достаточно просто, но для этого нужно иметь резервную копию базы. Когда у меня появились проблемы с базой, то я не мог зайти на сайт, и все мои статьи пропали. Пришлось срочно решать, как восстановить базу данных Wordprerss.

Такая ситуация у меня произошла пару дней назад, когда я писал 59 урок. Мне буквально через несколько минут пришло СМС от Яндекс-Метрики, что мой сайт не доступен. Если Вы с такой проблемой раньше сталкивались, то знаете как все вернуть в рабочее состояние, а если нет - читайте далее.

Как восстановить базу данных WordPress (способ 1)

В Интернете в основном пишут, как сделать резервную копию базы данных, но мало кто пишет, как восстановить базу данных WordPress . Не обязательно, что с базой данных могут возникнуть проблемы по Вашей вине. В базе могут возникнуть ошибки и по другим причинам.

Если на Вашем блоге еще не установлен плагин , или ему подобный, то Вы рискуете остаться без блога. Представьте, Вы ведете блог долгое время, а потом раз, и все! Амба! Этот плагин не позволит случится такому. Он сохраняет базу данных Вашего блога постоянно в автоматическом режиме и без Вашего участия.

Информации по восстановлению базы данных много в Интернете, но, бывает такую ерунду пишут, за которую люди еще и благодарят. Автор статьи дает советы, как правильно делать то и то, но сам даже не понимает, о чем пишет. Все, пора перейти к делу 🙂

Чтобы вернуть блог в прежнее состояние, у Вас должна быть свежая резервная копия базы данных. Распакуйте файл базы и откройте распакованный файл в блокноте Windows. Скопируйте содержимое фала в . Перейдите в панели управления на Вашем хостинге в PhpMyAdmin.

Щелкните по названию базы данных, которую хотите восснановить.

Потом нужно щелкнуть по "SQL " и вставьте в окошко то, что скопировали с файла базы данных, нажав "CTRL " + "V ". Нажмите потом "ОК ".

Подождав пока закончится восстановление базы данных. Должна появится надпись об успешном выполнении.

Теперь Ваш блог полностью восстановлен.

Как быстро восстановить базу данных WordPress (способ 2)

Итак, без лишних вступлений. Переходите на Вашем хостинге в контрольную панель (cPanel). Найдите ссылку «MySQL » или «PhpMyAdmin ».

Теперь нужно осуществить вход в панель управление базами данных, т. е. в PhpMyAdmin. Нажимаем «Войти »

Вы попадете в PhpMyAdmin. Слева щелкните по базе, которую собираетесь восстановить. В моем случае это база dvpress.

После того, как выберите базу, появятся все таблицы этой базы данных. Чтобы во время восстановления, не возникало никаких ошибок, надо эту базу полностью удалить. Опускаемся в самый низ и находим «Отметить все / Снять выделение ». Нажимаете на «Отметить все », чтобы все таблицах базы стояли галочки в чекбоксе. Выбираем в окошке правее «Удалить », а потом подтвердите "Да ". База данных должна полностью очиститься от всех таблиц.

Теперь Ваша задача восстановить эту базу из резервной копии. Жмите вверху «Импорт », потом щелкайте по кнопке «Выберите файл ». Найдите на своем компьютере резервную копию базы и нажмите «Открыть ». Теперь в PhpMyAdmin внизу нажмите «Ок ». Операция должна пройти успешно, о чем должна оповестить надпись «SQL запрос успешно выполнен ».

Которой я запостил на прошлой неделе, вызвала, вроде бы, определенный интерес, но она, увы, не содержала «практики». Да, там написано как можно спасти данные, но нет никаких примеров.
Изначально я хотел сделать еще один перевод все того же автора, но, подумав, решил написать пост «от себя», как бы «по мотивам». Причины, побудившие меня поступить так, я опишу в конце поста, в примечаниях.

Восстановление баз данных в SQL Server

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

SQL Server предоставляет множество возможностей для восстановления баз данных. Во-первых, это восстановление базы данных целиком - оно может занимать довольно много времени (зависит от размера БД и скорости жестких дисков). Во-вторых, восстановление отдельных файловых групп, либо файлов, если ваша БД состоит из нескольких файловых групп (или, соответствено, файлов). В этом случае, есть возможность восстановления только поврежденных частей БД, не затрагивая остальных. Эти два вида восстановления БД используются довольно часто и затрагиваться в дальнейшем не будут.
В-третьих, в SQL Server 2005 появилась возможность восстановления отдельных страниц БД - в этом случае из бэкапа будут восстановлены только указанные страницы. Такое восстановление будет особенно актуально, если DBCC CHECKDB найдет несколько поврежденных страниц в какой-нибудь огромной таблице, «лежащей» в здоровенном файле. За счет того, что восстанавливаться будет не весь файл, и даже не вся таблица, а только несколько страниц - время простоя может быть значительно сокращено.

Требования и ограничения

Модель восстановления и доступность резервных копий журнала транзакций
Самое главное, что нужно помнить - для восстановления отдельных страниц, база данных должна использовать полную (full) модель восстановления, либо модель восстановления с неполным протоколированием (bulk-logged). Если ваши базы находятся в простой (simple) модели восстановления - дальше вы можете уже и не читать.
Второе требование - ваши полные бэкапы и бэкапы журнала транзакций должны образовывать неразрывную цепочку журналов (log chain). Если вы никогда не выполняете команду BACKUP LOG WITH TRUNCATE_ONLY (NO_LOG) и не переключаетесь в простую модель восстановления для того, чтобы уменьшить журнал транзакций, и у вас есть ВСЕ резервные копии журнала транзакций с момента последней полной резервной копии не содержащей поврежденных страниц (включая эту самую полную резервную копию) - за цепочку журналов можно не волноваться.
В модели восстановления с неполным протоколированием, теоретически, восстановление отдельных страниц должно работать нормально в том случае, если соблюдаются условия описанные выше, и восстанавливаемые страницы не изменялись операциями, выполняемыми с минимальным протоколированием .
Редакции SQL Server
Восстановление страниц возможно в любой редакции SQL Server, но для редакций Enterprise Edition и Developer Edition возможно восстановление поврежденных страниц on-line, т.е. к базе данных, во время восстановления, можно обращаться (и более того, обращаться можно даже к той таблице, к которой относятся восстанавливаемые в данный момент страницы, если сами эти страницы не будут «затрагиваться» - в противном случае, запрос завершится ошибкой). Для редакций «ниже» Enterprise Edition, восстановление страниц проходит в режиме off-line и база данных, на время восстановления, становится недоступной.
Тип поврежденной страницы
В том случае если повреждены страницы индекса, либо данных, их восстановление возможно в режиме online в редакции Enterprise Edition.
Страницы, приндалежащие критически важным системным таблицам могут быть восстановлены, но база данных, при восстановлении, будет недоступна в любой редакции SQL Server.
«Карты размещения» не могут быть восстановлены «отдельно». Если повреждены GAM, SGAM, PFS, ML, DIFF-страницы, необходимо восстанавливать базу данных целиком. Единственным исключением являются IAM-страницы. Хотя они и относятся к «картам размещения», но они описывают только одну таблицу, а не всю базу данных, и их восстановление возможно.
Загрузочная страница базы данных (9-я страница в 1-м файле БД) и страница заголовка файла (0-я страница в каждом файле) не могут быть восстановлены «отдельно», при их повреждении придется восстанавливать БД целиком.

Собственно, восстановление

Теперь, наконец, переходим от теории к практике.
В первую очередь, для тренировки, нужна испорченная база данных.
Портим БД
Для экспериментов я буду использовать базу данных AdventureWorks, которая поставляется вместе с SQL Server. Если вы не устанавливали ее, при желании, можно скачать . Перевожу ее в модель восстановления full:
ALTER DATABASE AdventureWorks SET RECOVERY FULL убеждаюсь, что ошибок в ней еще нет:
DBCC CHECKDB("AdventureWorks") WITH NO_INFOMSGS, ALL_ERRORMSGS, DATA_PURITY и создаю полный бэкап:
BACKUP DATABASE AdventureWorks TO DISK = "D:\tmp\aw_backups\aw_full_ok1.bak"

В этой базе данных я создаю таблицу crash.
CREATE TABLE crash (txt varchar(1000)) Поле типа varchar мы и будем портить, для того, чтобы проверить что произойдет, если вдруг SQL Server обнаружит в нем не те данные, которые он сам туда записал.
Прежде чем что-то испортить, надо это чем-то заполнить. Я забиваю в созданную таблицу левые данные.
SET NOCOUNT ON DECLARE @i INT SET @i = 1 WHILE @i<100000 BEGIN INSERT INTO crash SELECT REPLICATE("a", 1000) SET @i = @i + 1 END SET NOCOUNT OFF Теперь делаю резервную копию журнала транзакций:
BACKUP LOG AdventureWorks TO DISK = "D:\tmp\aw_backups\aw_log_ok1.trn"

Теперь немного изменим данные:

Итак, все готово. Отсоединяем БД и открываем mdf-файл FAR"ом (или чем вам удобнее), ищем в нем строку «zzzzzzz» и заменяем несколько "z" на произвольные символы:


Теперь, когда БД испорчена, подсоединяем ее. И, да, я помню, что в предыдущей статье было четко сказано, что отсоединять/присоединять БД не стоит. Но в нашем случае это абсолютно «безопасно» - база данных в «suspect» не упадет.

Ищем ошибки
Итак, испорченная БД успешно вернулась в строй. Снова запустим проверку целостности:
DBCC CHECKDB("AdventureWorks") WITH NO_INFOMSGS, ALL_ERRORMSGS, DATA_PURITY В результате то, чего мы ждали (обязательно запоминайте номера поврежденных страниц! ):

Msg 8928, Level 16, State 1, Line 1
Object ID 1883153754, index ID 0, partition ID 72057594054246400, alloc unit ID 72057594061651968 (type In-row data): Page (1:20455) could not be processed. See other errors for details.
Msg 8939, Level 16, State 98, Line 1
Table error: Object ID 1883153754, index ID 0, partition ID 72057594054246400, alloc unit ID 72057594061651968 (type In-row data), page (1:20455). Test (IS_OFF (BUF_IOERR, pBUF->bstat)) failed. Values are 29493257 and -4.
CHECKDB found 0 allocation errors and 2 consistency errors in table "crash" (object ID 1883153754).
CHECKDB found 0 allocation errors and 2 consistency errors in database "AdventureWorks".
repair_allow_data_loss is the minimum repair level for the errors found by DBCC CHECKDB (AdventureWorks).
В данном случае повреждены сами данные, находящиеся в куче (index id = 0), поэтому SQL Server эти данные восстановить не сможет.
Сейчас у нас есть три варианта:

  1. Смириться с потерей данных и выполнить DBCC CHECKDB("AdventureWorks", REPAIR_ALLOW_DATA_LOSS)
  2. Сделать бэкап активной части журнала транзакций и восстановить БД целиком - в результате потери данных не будет, но это займет продолжительное время
  3. Сделать бэкап активной части журнала транзакций и восстановить только одну(!), поврежденную, страницу
Со вторым вариантом все должно быть понятно, а вот что произойдет если запустить DBCC CHECKDB или как восстанавливаются отдельные страницы - я покажу дальше.
Восстанавливаем поврежденную страницу
В первую очередь нам надо сделать бэкап заключительного фрагмента журнала транзакций (tail backup). При этом, если у вас Enterprise Edition, вы можете не добавлять параметр NORECOVERY, который переведет БД в состояние «restoring», поскольку эта редакция поддерживает on-line восстановление страниц. Более того, если у вас резервные копии журнала транзакций выполняются на регулярной основе, чтобы не нарушать цепочку журналов, в редакции Enterprise Edition, вы можете сделать COPY_ONLY бэкап.
Я же иду по пути off-line восстановления и выполняю:
BACKUP LOG AdventureWorks TO DISK = "D:\tmp\aw_backups\aw_log_fail3.trn" WITH NORECOVERY


Теперь, можно восстанавливать поврежденную страницу. В первую очередь, используем полный бэкап (aw_full_ok1.bak):

RESTORE DATABASE AdventureWorks PAGE = "1:20455" FROM DISK = "D:\tmp\aw_backups\aw_full_ok1.bak" WITH NORECOVERY
В итоге, имеем:

Обратите внимание на то, что необходимо использовать опцию NORECOVERY, поскольку нам предстоит еще накатывать на нее бэкапы журнала транзакций.
RESTORE LOG AdventureWorks FROM DISK = "D:\tmp\aw_backups\aw_log_ok1.trn" WITH NORECOVERY и
RESTORE LOG AdventureWorks FROM DISK = "D:\tmp\aw_backups\aw_log_fail3.trn" WITH RECOVERY


Вроде бы все прошло успешно, запускаем DBCC CHECKDB и…


Восстановление прошло успешно.
Обратите внимание, что время простоя сокращается за счет того, что из полного бэкапа мы восстанавливаем не всю БД, а только поврежденные страницы (если бы я восстанавливал бэкап целиком - бэкап восстановился бы за 8,5 секунд, но, чем больше размер БД - тем больше будет разница во времени). Счастливчики с SQL Server Enterprise Edition, использующие on-line восстановление, так же сэкономят время на восстановлении из бэкапов лога, а при off-line восстановлении, увы, журналы будут обрабатываться целиком.
Стоит так же добавить, что в SQL Server 2005, 2008, 2008 R2 восстановление отдельной страницы возможно только с помощью T-SQL, в Denali появилась возможность делать это через GUI.

А если все-таки DBCC CHECKDB?
На всякий случай я решил проверить что сделает SQL Server, если я запущу DBCC CHECKDB с параметром REPAIR_ALLOW_DATA_LOSS. Все та же ошибка:


Сначала переводим БД в режим SINGLE_USER:
ALTER DATABASE AdventureWorks SET SINGLE_USER А затем, запускаем восстановление:
DBCC CHECKDB("AdventureWorks", REPAIR_ALLOW_DATA_LOSS) WITH NO_INFOMSGS, ALL_ERRORMSGS, DATA_PURITY В итоге:
Repair: The page (1:20455) has been deallocated from object ID 1883153754, index ID 0, partition ID 72057594054246400, alloc unit ID 72057594061651968 (type In-row data).
Ага, SQL Server удалил «испорченную» страницу. Переводим БД в режим MULTI_USER, чтобы она стала доступной для всех и проверяем что пропало:

Учитывая, что размер страницы в SQL Server 8КБ, а для пользовательских данных доступно чуть меньше - то все закономерно, таблица «похудела» на 7 записей (в начале их было 99999). Поскольку на этой таблице не было кластерного индекса, данные могли храниться в произвольном порядке, т.е. мы даже не могли узнать какие данные будут потеряны.

Так почему, все-таки, не перевод?

Итак, почему это все-таки не перевод, а пост «по мотивам». Дело в том, что, в открытом доступе статьи «Page Restore» за авторством Gail Shaw нет. Есть такой раздел в книге SQL Server MVP Deep Dives vol.2, которая продается за довольно-таки ощутимые деньги (но, естественно, легко находится в интернетах) и я не уверен, что публиковать перевод - это эм… правильно что ли.
В общем, я прочитал статью, взял на заметку основные моменты, а потом уже сам писал текст и, попутно, проводил эксперимент по восстановлению. Надеюсь, кому-нибудь этот опыт был полезен.
И, господа, я искренне надеюсь, что если вы решите повторять этот эксперимент, то будете предельно осторожны (например, не будете эксперементировать с основной БД на production-сервере). Помните, что никакой ответственности за ваши действия я не несу.

Которой я запостил на прошлой неделе, вызвала, вроде бы, определенный интерес, но она, увы, не содержала «практики». Да, там написано как можно спасти данные, но нет никаких примеров.
Изначально я хотел сделать еще один перевод все того же автора, но, подумав, решил написать пост «от себя», как бы «по мотивам». Причины, побудившие меня поступить так, я опишу в конце поста, в примечаниях.

Восстановление баз данных в SQL Server

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

SQL Server предоставляет множество возможностей для восстановления баз данных. Во-первых, это восстановление базы данных целиком - оно может занимать довольно много времени (зависит от размера БД и скорости жестких дисков). Во-вторых, восстановление отдельных файловых групп, либо файлов, если ваша БД состоит из нескольких файловых групп (или, соответствено, файлов). В этом случае, есть возможность восстановления только поврежденных частей БД, не затрагивая остальных. Эти два вида восстановления БД используются довольно часто и затрагиваться в дальнейшем не будут.
В-третьих, в SQL Server 2005 появилась возможность восстановления отдельных страниц БД - в этом случае из бэкапа будут восстановлены только указанные страницы. Такое восстановление будет особенно актуально, если DBCC CHECKDB найдет несколько поврежденных страниц в какой-нибудь огромной таблице, «лежащей» в здоровенном файле. За счет того, что восстанавливаться будет не весь файл, и даже не вся таблица, а только несколько страниц - время простоя может быть значительно сокращено.

Требования и ограничения

Модель восстановления и доступность резервных копий журнала транзакций
Самое главное, что нужно помнить - для восстановления отдельных страниц, база данных должна использовать полную (full) модель восстановления, либо модель восстановления с неполным протоколированием (bulk-logged). Если ваши базы находятся в простой (simple) модели восстановления - дальше вы можете уже и не читать.
Второе требование - ваши полные бэкапы и бэкапы журнала транзакций должны образовывать неразрывную цепочку журналов (log chain). Если вы никогда не выполняете команду BACKUP LOG WITH TRUNCATE_ONLY (NO_LOG) и не переключаетесь в простую модель восстановления для того, чтобы уменьшить журнал транзакций, и у вас есть ВСЕ резервные копии журнала транзакций с момента последней полной резервной копии не содержащей поврежденных страниц (включая эту самую полную резервную копию) - за цепочку журналов можно не волноваться.
В модели восстановления с неполным протоколированием, теоретически, восстановление отдельных страниц должно работать нормально в том случае, если соблюдаются условия описанные выше, и восстанавливаемые страницы не изменялись операциями, выполняемыми с минимальным протоколированием .
Редакции SQL Server
Восстановление страниц возможно в любой редакции SQL Server, но для редакций Enterprise Edition и Developer Edition возможно восстановление поврежденных страниц on-line, т.е. к базе данных, во время восстановления, можно обращаться (и более того, обращаться можно даже к той таблице, к которой относятся восстанавливаемые в данный момент страницы, если сами эти страницы не будут «затрагиваться» - в противном случае, запрос завершится ошибкой). Для редакций «ниже» Enterprise Edition, восстановление страниц проходит в режиме off-line и база данных, на время восстановления, становится недоступной.
Тип поврежденной страницы
В том случае если повреждены страницы индекса, либо данных, их восстановление возможно в режиме online в редакции Enterprise Edition.
Страницы, приндалежащие критически важным системным таблицам могут быть восстановлены, но база данных, при восстановлении, будет недоступна в любой редакции SQL Server.
«Карты размещения» не могут быть восстановлены «отдельно». Если повреждены GAM, SGAM, PFS, ML, DIFF-страницы, необходимо восстанавливать базу данных целиком. Единственным исключением являются IAM-страницы. Хотя они и относятся к «картам размещения», но они описывают только одну таблицу, а не всю базу данных, и их восстановление возможно.
Загрузочная страница базы данных (9-я страница в 1-м файле БД) и страница заголовка файла (0-я страница в каждом файле) не могут быть восстановлены «отдельно», при их повреждении придется восстанавливать БД целиком.

Собственно, восстановление

Теперь, наконец, переходим от теории к практике.
В первую очередь, для тренировки, нужна испорченная база данных.
Портим БД
Для экспериментов я буду использовать базу данных AdventureWorks, которая поставляется вместе с SQL Server. Если вы не устанавливали ее, при желании, можно скачать . Перевожу ее в модель восстановления full:
ALTER DATABASE AdventureWorks SET RECOVERY FULL убеждаюсь, что ошибок в ней еще нет:
DBCC CHECKDB("AdventureWorks") WITH NO_INFOMSGS, ALL_ERRORMSGS, DATA_PURITY и создаю полный бэкап:
BACKUP DATABASE AdventureWorks TO DISK = "D:\tmp\aw_backups\aw_full_ok1.bak"

В этой базе данных я создаю таблицу crash.
CREATE TABLE crash (txt varchar(1000)) Поле типа varchar мы и будем портить, для того, чтобы проверить что произойдет, если вдруг SQL Server обнаружит в нем не те данные, которые он сам туда записал.
Прежде чем что-то испортить, надо это чем-то заполнить. Я забиваю в созданную таблицу левые данные.
SET NOCOUNT ON DECLARE @i INT SET @i = 1 WHILE @i<100000 BEGIN INSERT INTO crash SELECT REPLICATE("a", 1000) SET @i = @i + 1 END SET NOCOUNT OFF Теперь делаю резервную копию журнала транзакций:
BACKUP LOG AdventureWorks TO DISK = "D:\tmp\aw_backups\aw_log_ok1.trn"

Теперь немного изменим данные:

Итак, все готово. Отсоединяем БД и открываем mdf-файл FAR"ом (или чем вам удобнее), ищем в нем строку «zzzzzzz» и заменяем несколько "z" на произвольные символы:


Теперь, когда БД испорчена, подсоединяем ее. И, да, я помню, что в предыдущей статье было четко сказано, что отсоединять/присоединять БД не стоит. Но в нашем случае это абсолютно «безопасно» - база данных в «suspect» не упадет.

Ищем ошибки
Итак, испорченная БД успешно вернулась в строй. Снова запустим проверку целостности:
DBCC CHECKDB("AdventureWorks") WITH NO_INFOMSGS, ALL_ERRORMSGS, DATA_PURITY В результате то, чего мы ждали (обязательно запоминайте номера поврежденных страниц! ):

Msg 8928, Level 16, State 1, Line 1
Object ID 1883153754, index ID 0, partition ID 72057594054246400, alloc unit ID 72057594061651968 (type In-row data): Page (1:20455) could not be processed. See other errors for details.
Msg 8939, Level 16, State 98, Line 1
Table error: Object ID 1883153754, index ID 0, partition ID 72057594054246400, alloc unit ID 72057594061651968 (type In-row data), page (1:20455). Test (IS_OFF (BUF_IOERR, pBUF->bstat)) failed. Values are 29493257 and -4.
CHECKDB found 0 allocation errors and 2 consistency errors in table "crash" (object ID 1883153754).
CHECKDB found 0 allocation errors and 2 consistency errors in database "AdventureWorks".
repair_allow_data_loss is the minimum repair level for the errors found by DBCC CHECKDB (AdventureWorks).
В данном случае повреждены сами данные, находящиеся в куче (index id = 0), поэтому SQL Server эти данные восстановить не сможет.
Сейчас у нас есть три варианта:

  1. Смириться с потерей данных и выполнить DBCC CHECKDB("AdventureWorks", REPAIR_ALLOW_DATA_LOSS)
  2. Сделать бэкап активной части журнала транзакций и восстановить БД целиком - в результате потери данных не будет, но это займет продолжительное время
  3. Сделать бэкап активной части журнала транзакций и восстановить только одну(!), поврежденную, страницу
Со вторым вариантом все должно быть понятно, а вот что произойдет если запустить DBCC CHECKDB или как восстанавливаются отдельные страницы - я покажу дальше.
Восстанавливаем поврежденную страницу
В первую очередь нам надо сделать бэкап заключительного фрагмента журнала транзакций (tail backup). При этом, если у вас Enterprise Edition, вы можете не добавлять параметр NORECOVERY, который переведет БД в состояние «restoring», поскольку эта редакция поддерживает on-line восстановление страниц. Более того, если у вас резервные копии журнала транзакций выполняются на регулярной основе, чтобы не нарушать цепочку журналов, в редакции Enterprise Edition, вы можете сделать COPY_ONLY бэкап.
Я же иду по пути off-line восстановления и выполняю:
BACKUP LOG AdventureWorks TO DISK = "D:\tmp\aw_backups\aw_log_fail3.trn" WITH NORECOVERY


Теперь, можно восстанавливать поврежденную страницу. В первую очередь, используем полный бэкап (aw_full_ok1.bak):

RESTORE DATABASE AdventureWorks PAGE = "1:20455" FROM DISK = "D:\tmp\aw_backups\aw_full_ok1.bak" WITH NORECOVERY
В итоге, имеем:

Обратите внимание на то, что необходимо использовать опцию NORECOVERY, поскольку нам предстоит еще накатывать на нее бэкапы журнала транзакций.
RESTORE LOG AdventureWorks FROM DISK = "D:\tmp\aw_backups\aw_log_ok1.trn" WITH NORECOVERY и
RESTORE LOG AdventureWorks FROM DISK = "D:\tmp\aw_backups\aw_log_fail3.trn" WITH RECOVERY


Вроде бы все прошло успешно, запускаем DBCC CHECKDB и…


Восстановление прошло успешно.
Обратите внимание, что время простоя сокращается за счет того, что из полного бэкапа мы восстанавливаем не всю БД, а только поврежденные страницы (если бы я восстанавливал бэкап целиком - бэкап восстановился бы за 8,5 секунд, но, чем больше размер БД - тем больше будет разница во времени). Счастливчики с SQL Server Enterprise Edition, использующие on-line восстановление, так же сэкономят время на восстановлении из бэкапов лога, а при off-line восстановлении, увы, журналы будут обрабатываться целиком.
Стоит так же добавить, что в SQL Server 2005, 2008, 2008 R2 восстановление отдельной страницы возможно только с помощью T-SQL, в Denali появилась возможность делать это через GUI.

А если все-таки DBCC CHECKDB?
На всякий случай я решил проверить что сделает SQL Server, если я запущу DBCC CHECKDB с параметром REPAIR_ALLOW_DATA_LOSS. Все та же ошибка:


Сначала переводим БД в режим SINGLE_USER:
ALTER DATABASE AdventureWorks SET SINGLE_USER А затем, запускаем восстановление:
DBCC CHECKDB("AdventureWorks", REPAIR_ALLOW_DATA_LOSS) WITH NO_INFOMSGS, ALL_ERRORMSGS, DATA_PURITY В итоге:
Repair: The page (1:20455) has been deallocated from object ID 1883153754, index ID 0, partition ID 72057594054246400, alloc unit ID 72057594061651968 (type In-row data).
Ага, SQL Server удалил «испорченную» страницу. Переводим БД в режим MULTI_USER, чтобы она стала доступной для всех и проверяем что пропало:

Учитывая, что размер страницы в SQL Server 8КБ, а для пользовательских данных доступно чуть меньше - то все закономерно, таблица «похудела» на 7 записей (в начале их было 99999). Поскольку на этой таблице не было кластерного индекса, данные могли храниться в произвольном порядке, т.е. мы даже не могли узнать какие данные будут потеряны.

Так почему, все-таки, не перевод?

Итак, почему это все-таки не перевод, а пост «по мотивам». Дело в том, что, в открытом доступе статьи «Page Restore» за авторством Gail Shaw нет. Есть такой раздел в книге SQL Server MVP Deep Dives vol.2, которая продается за довольно-таки ощутимые деньги (но, естественно, легко находится в интернетах) и я не уверен, что публиковать перевод - это эм… правильно что ли.
В общем, я прочитал статью, взял на заметку основные моменты, а потом уже сам писал текст и, попутно, проводил эксперимент по восстановлению. Надеюсь, кому-нибудь этот опыт был полезен.
И, господа, я искренне надеюсь, что если вы решите повторять этот эксперимент, то будете предельно осторожны (например, не будете эксперементировать с основной БД на production-сервере). Помните, что никакой ответственности за ваши действия я не несу.
В продолжение темы:
Интернет

Во время пользования компьютером в системе создаётся множество временных файлов. Одна часть удаляется после закрытия программ и перезагрузки ПК, а другая — так и остаётся...

Новые статьи
/
Популярные