Эта страница переведена машинным переводом. Читайте английский оригинал. English

Библиотека IBSurgeon

Руководство по восстановлению InterBase и Firebird

NOTICE: Этот документ является главой из книги “The InterBase World”, написанной Алексеем Ковязиным и Сергом Востриковым.

Глава из книги “The InterBase World”, посвященная восстановлению баз данных.

1. История создания этого руководства

Русская книга “The InterBase World” была опубликована в сентябре 2002 года.

Её тираж составил 3000 экземпляров. Через 3 месяца она была распродана, и в апреле 2003 года было опубликовано второе, улучшенное издание тиражом 5000 экземпляров.

Сейчас она находится на вершине рейтингов крупнейших российских интернет-магазинов книг, и мы предполагаем, что она будет распродана очень скоро.

Авторами книги являются Алексей Ковязин, разработчик IBSurgeon и

известный российский специалист по InterBase, и Серг Востриков, генеральный директор компании Devrace

www.devrace.com

Забавно, что ни одной книги, посвященной InterBase, не было опубликовано на английском языке!

Тысячи и тысячи разработчиков используют InterBase и Firebird, обсуждают эту

тему на различных конференциях (посмотрите здесь: Ссылки).

Сообщество разработчиков InterBase насчитывает в среднем десятки тысяч

человек. Высокий спрос на книги по InterBase в разных странах доказывает, что сообщество InterBase действительно велико.

Мы можем поспорить на ящик пива, что тираж в 10000 экземпляров будет сметён с Amazon.com за месяц. Но люди в издательских компаниях

“знают всё” и уверены, что никто не купит книгу об InterBase. Это очень жаль.

Здесь мы хотели бы предложить вам черновик одной главы этой книги, посвященной восстановлению баз данных InterBase/Firebird.

2. Как восстановить базу данных InterBase/Firebird

2.1. Обзор основных причин повреждения базы данных

К сожалению, всегда существует вероятность того, что любое хранилище информации будет

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

Прежде всего, если мы говорим о восстановлении базы данных, следует уточнить понятие

“повреждение базы данных”. База данных обычно называется поврежденной, если при попытке извлечь или изменить некоторую информацию появляются ошибки и/или извлекаемая информация оказывается потерянной, неполной или вовсе неверной. Бывают случаи, когда повреждения базы данных скрыты и обнаруживаются только при тестировании специальными средствами, но также существуют реальные повреждения базы данных, когда невозможно подключиться к базе данных, когда настроенные программы-клиенты показывают странные ошибки (когда никаких манипуляций с базой данных не выполнялось), или когда невозможно восстановить базу данных из резервной копии.

2.2. Основными причинами повреждения базы данных являются:

  • Аварийное завершение работы серверного компьютера, особенно перебои с электропитанием. Для IT-индустрии это настоящее бедствие, и поэтому мы надеемся, что нет необходимости напоминать вам еще раз о необходимости наличия источника бесперебойного питания на сервере.
  • Дефекты и неисправности серверного компьютера, особенно жесткого диска (HDD), дисковых контроллеров, оперативной памяти компьютера и кэш-памяти RAID-контроллеров.
  • Неправильная строка подключения к многоклиентской базе данных одного или нескольких пользователей (в версиях до 6.x). При подключении через TCP/IP путь к базе данных должен указываться как имя_сервера: диск:/путь/имя_базы_данных (для серверов на платформе UNIX имя_сервера: /путь/имя_базы_данных), согласно протоколу NETBEUI \\имя_сервера\диск:\путь\имя_базы_данных. Даже при подключении к базе данных с компьютера, на котором расположена база данных и работает сервер, следует использовать ту же строку, заменяя имя_сервера на localhost. Нельзя использовать сопоставленные диски в строке подключения. Если нарушить одно из этих правил, сервер считает, что работает с разными базами данных, и повреждение базы данных гарантировано.
  • Копирование файла или другой доступ к файлу базы данных при работающем сервере. Выполнение команды “shut-down” или отключение пользователей обычным способом не является гарантией того, что сервер ничего не делает с базой данных, если интервал сборки мусора (sweep interval) не установлен в “0”, может выполняться сборка мусора. Обычно сборка мусора выполняется сразу после отключения последнего пользователя от базы данных. Обычно это занимает несколько секунд, но если перед этим было зафиксировано много операций DELETE или UPDATE, процесс может быть более длительным.
  • Использование нестабильных версий сервера InterBase 5.1-5.5. Компания Borland официально признала, что в этих серверах было несколько ошибок, и стабильное обновление 5.6 было удалено только после выхода сертифицированного InterBase 6 в свободном режиме для всех клиентов серверов 5.1-5.5 на её сайте.
  • Превышение ограничения размера файла базы данных (не базы данных!). Для версий до InterBase 6 и некоторых бета-версий InterBase 6 предел файла базы данных составляет 4 ГБ, для InterBase 6.5 и всех выпусков Firebird (1.0, 1.5, 2.0, 2.1) - 32 ТБ. При приближении размера базы данных к предельному значению необходимо создать дополнительный файл.
  • Исчерпание свободного дискового пространства при работе с базой данных.
  • Для серверов Borland InterBase версий ниже 6.0.1.6 - превышение ограничения на количество генераторов, определенного отделом исследований и разработок Borland InterBase следующим образом (смотрите таблицу 1).
Версия Размер страницы=1024 Размер страницы=2048 Размер страницы=4096 Размер страницы=8192
До 6 248 504 1016 2040
6.0.x 124 257 508 102

Таблица 1: Критическое количество генераторов в ранних версиях InterBase

• Для всех серверов Borland InterBase - превышение допустимого количества

транзакций без выполнения резервного копирования/восстановления. Узнать количество транзакций, произошедших в базе данных с момента последнего создания, можно, вызвав утилиту gstat с ключом -h - параметр NEXT TRANSACTION ID будет искомым количеством транзакций. По словам Энн У. Харрисон, критическое количество транзакций зависит от размера страницы и имеет следующие значения (смотрите таблицу 2):

Размер страницы базы данных Критическое количество транзакций
1024 байта 131 596 287
2048 байт 265 814 016
4096 байт 534 249 472
8192 байта 1 071 120 384

Таблица 2: Критическое количество транзакций в серверах Borland InterBase

Ограничения серверов Borland InterBase, перечисленные выше, не применяются к

серверам Firebird, за исключением самых ранних версий 0.x, существование которых уже стало историей. Если вы используете финальную версию Firebird 1.0 или InterBase 6.5-7.x, вам не следует беспокоиться о пунктах 5, 6, 8 и 9, и вам следует сосредоточить свои усилия на других причинах. Теперь мы рассмотрим наиболее частые из них подробно.

2.3. Сбой электропитания

При отключении питания на сервере все операции по обработке данных

прерываются в самых неожиданных и (согласно закону Мерфи) опасных местах. В результате информация в базе данных может быть искажена или потеряна. Самый простой случай - когда все незафиксированные данные от клиентских приложений были потеряны в результате аварийного завершения работы сервера. После перезапуска после сбоя питания сервер анализирует данные, замечает незавершенные транзакции, не относящиеся ни к одному из клиентов, и отменяет все изменения, сделанные в рамках этих «мертвых» транзакций. На самом деле такое поведение является нормальным и предполагалось изначально разработчиками InterBase.

Однако перебои с электропитанием не всегда сопровождаются только такими незначительными потерями. Если сервер выполнял расширение базы данных в момент перебоя с электропитанием, существует большая вероятность появления осиротевших страниц в файле базы данных (страниц, которые физически выделены и зарегистрированы на странице инвентаризации страниц (PIP), запись данных на которые невозможна). Если вы хотите узнать больше об осиротевших страницах, смотрите главу «Структура базы данных InterBase».

Только инструмент восстановления и модификации gfix (мы рассмотрим его ниже) способен бороться с осиротевшими страницами в файле базы данных. На самом деле осиротевшие страницы приводят к лишнему расходу дискового пространства и как таковые не являются причиной потери или повреждения данных.

Потеря питания приводит к более серьёзным повреждениям. Например, после отключения питания и перезапуска может быть потеряно большое количество данных, включая зафиксированные (после добавления или изменения которых была выполнена команда «commit transaction»). Это происходит потому, что подтверждённые данные не записываются напрямую в файл базы данных на диске. Для этой цели используется файловый кэш операционной системы (ОС). Серверный процесс отдал команду записи данных ОС. Затем ОС заверила сервер, что все данные сохранены на диске, а на самом деле данные были сохранены в файловом кэше. ОС не спешит сбрасывать эти данные на диск, поскольку считает, что в основной памяти ещё много места, и откладывает медленные операции записи на диск до тех пор, пока основная память не заполнится.

2.4. Принудительные записи - палка о двух концах

Чтобы повлиять на ситуацию, в InterBase 6 предусмотрена настройка режима записи данных. Этот параметр называется forced writes (FW) и имеет 2 режима - ON (синхронный) и OFF (асинхронный). Режимы FW определяют, как InterBase взаимодействует с диском. Если FW включён, включается настройка синхронной записи на диск, когда подтверждённые данные записываются на диск сразу после команды commit, сервер ожидает завершения записи и только затем продолжает обработку. Если FW выключен, InterBase не спешит записывать данные на диск после команды фиксации транзакции и делегирует эту задачу параллельному потоку, в то время как основной поток продолжает обработку данных, не дожидаясь завершения записи на диск. Режим синхронной записи является одним из самых осторожных и сводит к минимуму возможную потерю данных, однако он может привести к некоторой потере производительности. Режим асинхронной записи увеличивает вероятность потери большого объёма данных. Для достижения максимальной производительности обычно устанавливается режим FW Off. Но в результате перебоя питания при асинхронной записи теряется гораздо больше данных, чем при синхронной. При настройке режима записи следует решить, важнее ли несколько процентов производительности, чем несколько часов работы, если неожиданно произойдёт перебой питания.

Очень часто пользователи небрежно относятся к InterBase. Небольшие организации экономят на любой мелочи, часто на компьютере-сервере, где установлены сервер СУБД и различные серверные программы (и не только серверные). Если они зависают, люди, недолго думая, нажимают RESET (это происходит несколько раз в день). Хотя InterBase очень устойчив к таким действиям по сравнению с другими СУБД и позволяет начать работу с базой данных сразу после аварийной перезагрузки, такое использование нежелательно. В результате ошибочных перезагрузок увеличивается количество осиротевших страниц, и данные теряют связи между собой.

Это может продолжаться долго, но рано или поздно всему придёт конец. Когда повреждённые страницы появляются среди страниц PIP или генераторов, или если повреждена страница заголовка базы данных, база данных может больше никогда не открыться и превратиться в большой кусок разрозненных данных, из которого нельзя извлечь ни одного байта полезной информации.

2.5. Повреждение жёсткого диска

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

2.6. Ошибки проектирования базы данных

Необходимо знать о некоторых ошибках, допускаемых разработчиками баз данных, которые могут привести к невозможности восстановления базы данных из резервной копии (файлы *.gbk, созданные программой gbak). Прежде всего, это небрежное использование ограничений на уровне базы данных. Типичный пример - ограничение NOT NULL. Предположим, у нас есть таблица, заполненная определённым количеством записей. Теперь мы добавим в эту таблицу с помощью команды ALTER TABLE ещё один столбец и укажем, что он не должен содержать неопределённых значений NULL. Примерно так:

ALTER TABLE sometable Field/INTEGER NOT NULL

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

Однако если мы сделаем резервную копию базы данных и попытаемся восстановить её из резервной копии, мы получим сообщение об ошибке на этапе восстановления (поскольку в столбец с ограничением NOT NULL вставляются значения NULL, и процесс восстановления будет прерван. (Важное примечание от Крейга Стунца - в версии InterBase 7.1 ограничения по умолчанию игнорируются при восстановлении (этим можно управлять с помощью параметра командной строки), и почти любая неповреждённая резервная копия может быть восстановлена. Всегда полезно выполнять тестовое восстановление после создания резервной копии, но в версии 7.1 эта проблема должна практически исчезнуть.) Эту резервную копию невозможно восстановить. Если восстановление было направлено в файл с тем же именем, что и существующая база данных (во время восстановления рабочий файл существующей базы данных перезаписывался), мы потеряем всю информацию.

Это связано с тем, что ограничения NOT NULL реализованы системными триггерами, которые проверяют только поступающие данные. При восстановлении данные из резервной копии вставляются в пустые только что созданные таблицы - здесь мы можем обнаружить недопустимые NULL в столбце с ограничением NOT NULL.

Некоторые разработчики считают такое поведение InterBase некорректным, но другие не смогут добавить поле с ограничением NOT NULL в таблицу базы данных.

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

Аналогичная проблема может быть вызвана сбоем сборки мусора из-за указания неправильного пути к базе данных (причина повреждения 3) при подключении и доступе к файлам базы данных, когда сервер работает с ней (причина повреждения 4), и в некоторых таблицах могут появиться записи, полностью заполненные NULL. Эти записи очень трудно обнаружить, поскольку они не соответствуют ограничениям контроля целостности, и оператор Select просто их не видит, хотя они попадают в резервную копию. Если восстановление по этой причине невозможно, следует запустить программу gfix (см. ниже), найти и удалить эти записи, используя в качестве условий поиска неиндексированные поля, после чего повторить попытку создания резервной копии и восстановления базы данных из неё. В заключение можно сказать, что существует большое количество причин повреждения базы данных, и вы всегда должны быть готовы к худшему - что ваша база данных будет повреждена по той или иной причине. Вы также должны быть готовы восстановить и сохранить ценную информацию. А теперь мы рассмотрим меры предосторожности, гарантирующие безопасность базы данных InterBase, а также методы восстановления повреждённых баз данных.

2.7. Меры предосторожности против повреждения базы данных InterBase

Чтобы предотвратить повреждение базы данных, всегда следует создавать резервные копии (если вы хотите узнать больше о резервном копировании, обратитесь к главе «Резервное копирование и восстановление»). Это самый надёжный способ защиты от повреждения базы данных. Только резервная копия даёт 100% гарантию безопасности базы данных. Как описано выше, в результате резервного копирования мы можем получить бесполезную копию (копию, которую невозможно восстановить), поэтому восстановление базы из копии не должно выполняться путём перезаписи скрипта, и резервное копирование должно выполняться по определённым правилам. Во-первых, резервное копирование должно выполняться как можно чаще, во-вторых, оно должно быть последовательным, и в-третьих, резервные копии должны проверяться на возможность восстановления.

Часто резервное копирование означает, что необходимо создавать резервную копию довольно часто, например, раз в двадцать четыре часа. Чем меньше период данных между резервными копиями базы данных, тем меньше данных будет потеряно в результате сбоя. Последовательность резервного копирования означает, что количество резервных копий должно увеличиваться и храниться как минимум в течение недели. Если есть возможность, необходимо записывать резервные копии на специальные устройства, такие как стример, а если нет - просто копировать их на другой компьютер. История резервных копий поможет обнаружить скрытые повреждения и справиться с ошибкой, возникшей давно и проявившейся неожиданно. Нужно проверять, можно ли восстановить полученную резервную копию без ошибок или нет. Это можно проверить только одним способом - через процесс тестового восстановления. Следует сказать, что процесс восстановления занимает в 3 раза больше времени, чем резервное копирование, и выполнять проверку восстановления каждый день для больших баз данных сложно, поскольку это может прервать работу пользователей на несколько часов (ночного перерыва может не хватить).

Было бы лучше, если бы крупные организации не экономили на «спичках» и оставляли один компьютер для этих целей.

В этом случае, если сервер должен работать с серьёзной нагрузкой 24 часа 7 дней в неделю, мы можем использовать механизм SHADOW для создания снимков базы данных и дальнейших операций резервного копирования с непосредственной копии. Процесс резервного копирования и восстановления базы данных подробно описан в главе «Резервное копирование и восстановление». При создании резервной копии и последующем восстановлении базы данных из неё происходит воссоздание всех данных в базе. Этот процесс (backup/restore или b/r) способствует исправлению большинства нефатальных ошибок в базе данных, связанных с повреждениями жёсткого диска, выявлению проблем с целостностью базы данных, очистке базы от мусора (старых версий и фрагментов записей, незавершённых транзакций), значительному уменьшению размера базы данных.

Регулярное выполнение b/r является гарантией безопасности базы данных InterBase. Если база данных работает, рекомендуется выполнять b/r каждую неделю. По правде говоря, существуют примеры баз данных InterBase, которые интенсивно использовались в течение многих лет без резервного копирования и восстановления.

Тем не менее, чтобы быть в безопасности, желательно выполнять эту процедуру, тем более что её легко автоматизировать (см. главу «Резервное копирование»).

Если по каким-то причинам невозможно часто выполнять резервное копирование/восстановление, можно использовать инструмент gfix для проверки и восстановления базы данных. gfix позволяет проверить и устранить многие ошибки без выполнения b/r.

2.8. Инструмент командной строки gfix

Инструмент командной строки gfix используется для проверки и восстановления базы данных. Кроме того, gfix может выполнять различные операции управления базой данных: изменение диалекта базы данных, установку и отмену режима «только для чтения», установку размера кэша для конкретной базы данных, а также некоторые важные функции (о них можно узнать в InterBase 6 Operations Guide [4.). gfix запускается в режиме командной строки и имеет следующий синтаксис:

Gfix [опции] имя_бд

Опции - это набор опций для выполнения gfix, имя_бд - это имя базы данных, над которой будут выполняться операции, определяемые набором опций. Таблица 3 представляет опции gfix, относящиеся к восстановлению базы данных:

Опция Описание
-f[ull] Эта опция используется в сочетании с -v и
означает, что пришло время проверить все фрагменты записей
-i[gnore] Опция заставляет gfix игнорировать ошибки контрольных сумм при
проверке или очистке базы данных
-m[end] Помечает повреждённые записи как недоступные, в
результате чего они будут удалены при последующем
резервном копировании/восстановлении. Опция используется при
подготовке повреждённой базы данных к b/r.
-n[o_update] Опция используется в сочетании с -v для
проверки базы данных только для чтения без исправления
повреждений
-pas[sword] Опция позволяет задать пароль при
подключении к базе данных. (Обратите внимание, что в документации InterBase ошибка -pa[ssword], но сокращение “-pa” не будет работать - используйте “-pas”)
-user Опция позволяет задать имя пользователя, подключающегося
к базе данных
-v[alidate] Опция, задающая проверку базы данных, в
результате которой выявляются ошибки
-m[ode] Опция, задающая режим записи для базы данных -
только для чтения или чтение/запись. Этот параметр может
принимать 2 значения - read write или read only.
-w[rite] {sync | async} Опция, включающая и отключающая режим
синхронной/асинхронной принудительной записи в
базу данных. sync - включить синхронную запись
(FW ON); async - включить асинхронную запись
(FW OFF);

Таблица 1: Опции инструмента gfix для восстановления базы данных

Существуют некоторые типичные примеры использования gfix:

gfix -w sync -user SYSDBA -pass masterkey firstbase.gdb

В этом примере мы устанавливаем для нашей тестовой базы данных firstbase.gdb режим синхронной записи (FW ON). (Конечно, это полезно сделать до возникновения повреждения). А ниже приведена первая команда, которую следует использовать для проверки базы данных после возникновения повреждения:

gfix -v -full -user SYSDBA -pass masterkey firstbase.gdb

В этом примере мы запускаем проверку нашей тестовой базы данных (опция -v) и указываем, что фрагменты записей также должны быть проверены (опция -full). Конечно, удобнее задавать различные опции для процесса проверки и восстановления с помощью какого-либо графического интерфейса, но мы рассмотрим функции восстановления базы данных с помощью инструментов командной строки. Эти инструменты входят в состав InterBase, и вы можете быть уверены, что их поведение будет одинаковым на всех ОС, работающих с InterBase. Очень важно, чтобы они всегда были под рукой.

Кроме того, существующие инструменты, позволяющие выполнять администрирование базы данных с клиентского компьютера, используют для этого Services API, который не поддерживается архитектурой Classic сервера InterBase. Это означает, что вы можете использовать сторонние продукты с архитектурой сервера SuperServer.

2.9. Восстановление повреждённой базы данных

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

Следует остановить сервер InterBase, если он ещё работает, и сделать копию файла или файлов базы данных. Все операции восстановления должны выполняться только с копией базы данных, потому что выбранный способ может привести к неудачному результату, и вам придётся начинать процедуру восстановления заново (с исходной точки). После создания копии мы выполним полную проверку базы данных (проверку фрагментов записей).

Для этого следует выполнить следующую команду:

gfix -v - full corruptbase gdb -user SYSDBA - password

В этом случае corruptbase.gdb - это копия повреждённой базы данных. Команда проверит базу данных на наличие структурных повреждений и выдаст список нерешённых проблем. Если такие ошибки обнаружены, нам придётся удалить повреждённые данные и подготовиться к резервному копированию/восстановлению с помощью следующей команды:

gfix -mend -user SYSDBA -password your_masterkey corruptbase gdb

После выполнения команды следует проверить, остались ли в базе данных ошибки. Для этого необходимо запустить gfix с опциями -v -full, а когда процесс завершится, выполнить резервное копирование базы данных:

gbak -b -v -ig -user SYSDBA -password corruptbase.gdb corruptbase.gbk

Эта команда выполнит резервное копирование базы данных (об этом говорит опция - b), и мы получим подробную информацию о ходе выполнения резервного копирования (опция -v). Ошибки, связанные с контрольными суммами, будут игнорироваться (опция - ig). Если вы хотите узнать больше об опциях инструмента командной строки gbak, вы можете найти это в главе «Резервное копирование и восстановление». Если при резервном копировании возникнут ошибки, следует запустить его в другой конфигурации:

gbak -b -v -ig -g -user SYSDBA -password corruptbase.gdb

corruptbase.gbk

Где опция - g отключит сборку мусора во время резервного копирования. Это часто помогает решить проблему с резервным копированием.

Также возможно выполнить резервное копирование базы данных, если перед этим перевести базу в режим только для чтения. Этот режим предотвращает запись любых изменений в базу данных и иногда помогает выполнить резервное копирование повреждённой базы. Для установки режима только для чтения следует использовать следующую команду: gfix -m read _only

-user SYSDBA -password masterkey Disk:\Path\file.gdb

После этого следует снова попытаться выполнить резервное копирование базы данных, используя параметры, приведённые выше.

Если резервное копирование прошло успешно, следует восстановить базу данных из резервной копии. Для этого следует использовать следующую команду:

gbak -c -user SYSDBA -password masterkey Disk:\Path\backup.gbk

Disk:\Path\newbase,gdb

При восстановлении базы данных могут возникнуть некоторые проблемы, особенно при создании индексов. В этом случае к команде восстановления следует добавить опции -inactive и -one_at_a_time. Эти опции деактивируют индексы, создаваемые из резервной копии базы данных, и фиксируют подтверждение данных для каждой таблицы.

2.10. Как можно попытаться извлечь данные из повреждённой базы данных

Возможно, что операции, приведённые выше, не приведут к восстановлению базы данных.

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

Итак, перед переносом данных из старой базы данных необходимо создать базу назначения. Если база данных не изменялась в течение длительного времени, можно использовать старую резервную копию, из которой можно извлечь метаданные для создания базы назначения. На основе этих метаданных нужно создать базу данных назначения и начать копирование данных. Основная задача - извлечь данные из повреждённой базы данных. Затем нам придётся разместить данные в новой базе, но это не очень сложно, даже если придётся восстанавливать структуру базы данных по памяти. При извлечении данных из таблиц следует использовать следующий алгоритм операций:

  • Сначала следует попытаться выполнить SELECT* из таблицы N. Если это прошло нормально, вы можете сохранить полученные данные во внешнем источнике. Лучше хранить данные в скрипте (почти все GUI предоставляют эту функцию), если только таблица не содержит BLOB-полей. Если в таблице есть BLOB-поля, то данные из них следует сохранить в другую базу данных с помощью клиентской программы, которая будет играть роль посредника. Возможно, вам придётся написать эту тривиальную программу специально для целей восстановления данных.
  • Если вам не удалось получить все данные, следует удалить все индексы и попробовать снова. По сути, индексы можно удалить из всех таблиц с самого начала восстановления, поскольку они больше не понадобятся. Конечно, если у вас нет структуры метаданных, идентичной повреждённой, необходимо вести протокол всех операций, которые вы выполняете с повреждённой базой данных-источником.
  • Если вам не удаётся прочитать все данные из таблицы после удаления индексов, можно попробовать выполнить запрос диапазона по первичному ключу. Это означает выбор определённого диапазона данных. Например:

SELECT * FROM table N WHERE field_PK >=0 and field_PK <=10000 Field_PK

здесь - первичный ключ. InterBase имеет страничную организацию данных, и поэтому запрос диапазона значений может быть довольно эффективным, хотя это кажется чем-то вроде шаманства. Тем не менее это работает, потому что мы можем исключить данные из запроса с повреждённых страниц и, к счастью, прочитать остальные. Вы можете вспомнить наш тезис о том, что в SQL нет определённого порядка хранения записей. Действительно, никто не гарантирует, что неупорядоченный запрос при повторных запусках вернёт записи в том же порядке, но тем не менее физические записи хранятся в базе данных в определённом внутреннем порядке. Очевидно, что сервер не будет перемешивать записи просто для соблюдения стандарта SQL. Можно попробовать использовать этот внутренний порядок при извлечении данных из повреждённой базы данных (если вы хотите узнать больше информации о страницах данных и их взаимосвязях, обратитесь к главе «Структура базы данных InterBase»).

Виталий Бармин, один из опытных российских разработчиков InterBase, сообщил, что таким образом ему удалось восстановить до 98% информации из невосстановимой базы данных (там было большое количество повреждённых страниц). Таким образом, данные из повреждённой базы данных должны быть перенесены в новую базу данных или во внешние источники, такие как SQL-скрипты. При копировании данных обратите внимание на значения генераторов в повреждённой базе данных (они должны быть сохранены для перезапуска правильной работы в новой базе данных. Если у вас нет полной копии метаданных, следует извлечь тексты хранимых процедур, триггеров, ограничений и определения индексов.

2.11. Восстановление безнадёжной базы данных

В целом восстановление базы данных может быть очень хлопотным и сложным, и поэтому лучше сделать резервную копию базы данных, чем восстанавливать повреждённые данные, и что бы ни случилось, не следует отчаиваться, потому что решение можно найти в самых сложных ситуациях. И сейчас мы рассмотрим 2 случая.

Первый случай (классическая проблема). Резервная копия, которую невозможно восстановить из-за наличия NULL-значений в столбце с ограничением NOT NULL (процесс восстановления выполнялся поверх рабочего файла). Рабочий файл был стёрт, и процесс восстановления был прерван из-за ошибки. И в результате необдуманных действий мы получили большое количество бесполезных данных (которые невозможно восстановить) вместо резервной копии. Но решение было найдено. Программисту удалось вспомнить, какая таблица и какой столбец имели ограничение NOT NULL. Файл резервной копии был загружен в шестнадцатеричный редактор. И комбинация байтов, соответствующая определению этого столбца, была найдена там путём поиска. После бесчисленных экспериментов выяснилось, что ограничение NOT NULL добавляет 1 где-то рядом с именем столбца. В HEX-редакторе эта «1» была исправлена на «0», и резервная копия была восстановлена. После этого случая программист запомнил раз и навсегда, как выполнять процесс резервного копирования и восстановления.

Второй случай. Ситуация была катастрофической. База данных была повреждена на этапе расширения из-за нехватки дискового пространства. При увеличении размера базы данных сервер создаёт серию критически важных страниц (например, страницу инвентаризации транзакций и страницу инвентаризации страниц, дополнительные страницы для отношения RDB$Pages) и записывает их в конец базы данных. В результате база данных не открывалась ни средствами администрирования, ни утилитой GBAK. И при попытке подключиться к базе данных появлялось сообщение об ошибке («Unexpected end of file»).

Когда мы запускали утилиту gfix, происходили странные вещи: программа работала в бесконечном цикле. Пока работал gfix, сервер записывал ошибки в журнал (файл InterBase log) с высокой скоростью (около 100 Кб в секунду). В результате файл журнала очень быстро заполнял всё свободное дисковое пространство. Нам даже пришлось написать программу, которая стирала этот журнал по таймеру. Этот процесс длился долго - gfix работал более 16 часов без каких-либо результатов. Журнал был заполнен ошибками следующего вида: «Page XXX doubly allocated». В исходных текстах InterBase (в файле val.#) есть краткое описание этой ошибки. Там говорится, что эта ошибка появляется, когда одна и та же страница данных используется дважды. Очевидно, что эта ошибка является результатом повреждения критически важных страниц.

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

Александр Козельский, начальник отдела информационных технологий компании East View Publications Inc, является автором идеи извлечения информации из подобных невосстановимых баз данных.

Метод восстановления, который мы получили в результате исследований, был основан на том факте, что база данных имеет страничную организацию, и данные из каждой таблицы собираются по страницам данных. Каждая страница данных содержит идентификатор таблицы, для которой она хранит данные. Особенно важно было восстановить данные из нескольких критических таблиц. Там были данные из аналогичных таблиц, полученные из старой резервной копии, которая работала отлично и могла служить образцом. База данных-образец была загружена в редактор шестнадцатеричных источников, и затем мы искали образцы тех данных, которые нас интересовали. Эти данные были скопированы в буфер в шестнадцатеричном формате, а затем остатки повреждённой базы данных были загружены в редактор. Последовательность байтов, соответствующая образцу, была найдена в повреждённой базе данных, и страница (на которой была найдена эта последовательность) была проанализирована.

Сначала мы определили начальную страницу, но это было несложно, поскольку размер файла базы данных делится на размер страницы данных. Номер текущего байта, разделённый на размер страницы - 8192 байта, приближает результат к целому числу (и получаем номер текущей страницы). Затем умножили номер текущей страницы на размер страницы и получили номер байта, соответствующий началу текущей страницы. Проанализировав заголовок, мы определили тип страницы (для страниц с данными тип равен 5 - смотрите файл ods.h из набора исходных текстов InterBase, а также главу «Структура базы данных InterBase»), а также идентификатор необходимой таблицы.

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

Таким образом, когда мы получили необходимые данные в первую очередь, мы начали анализировать содержимое выбранных страниц. InterBase широко использует сжатие данных для экономии места. Например, строка типа VARCHAR, содержащая строку «ABC», хранит последовательность следующих значений: длина строки (2 байта), в нашем случае это 0003, затем сами символы и контрольная сумма. Нам пришлось написать анализатор строк, а также других типов данных базы, который преобразовывал данные из шестнадцатеричного формата в обычный вид. Нам удалось извлечь до 80% информации из нескольких критически важных таблиц с помощью «ручного» метода анализа содержимого базы данных. Позже, на основе этого опыта, Олег Кульков и Алексей Ковязин, один из авторов этой книги, разработали утилиту InterBase Surgeon, которая осуществляет прямой доступ к базе данных, минуя движок InterBase, и позволяет правильно читать и интерпретировать данные внутри базы данных InterBase.

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

Вы можете загрузить эту программу с официального сайта программы www.ib-aid.com.

3. Благодарности

Я хотел бы выразить благодарность всем, кто помог мне создать это руководство:

Крейг Стунц, Александр Невский, Константин Сипачев, Татьяна Сипачева и все другие добрые и знающие люди из сообщества InterBase и Firebird.

Если у вас есть какие-либо предложения или вопросы по этой главе, пожалуйста, не стесняйтесь писать по электронной почте.

© 2002 Алексей Ковязин, Сергей Востриков.

Copyright © 2004 IBSurgeon Team. Все права защищены.