此页面为机器翻译。请阅读英文原文。 English

IBSurgeon 文库

InterBase 和 Firebird 恢复指南

NOTICE: 本文档是《The InterBase World》一书中的章节,该书由 Alexey Kovyazin 和 Serg Vostrikov 撰写。

《The InterBase World》一书中专门讨论数据库修复的章节。

1. 本指南的历史

俄文版《The InterBase World》于2002年9月出版。

首印3000册。3个月后即告售罄,第二版(修订版)于2003年4月出版,印量5000册。

目前该书在俄罗斯最大的在线书店中位居榜首,我们预计它很快将再次售罄。

本书作者为 Alexey Kovyazin(IBSurgeon 开发者、俄罗斯知名 InterBase 专家)和 Serg Vostrikov(Devrace 公司 CEO,www.devrace.com)。

有趣的是,至今还没有一本专门介绍 InterBase 的英文书籍出版!

成千上万的开发者使用 InterBase 和 Firebird,在各种会议中讨论相关话题(参见:Links)。

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.1-5.5 服务器客户端免费提供了稳定的升级版本 5.6(仅在认证版 InterBase 6 发布后推出)。
  • 超出数据库文件(而非数据库本身!)的大小限制。对于 InterBase 6 之前的版本和某些 InterBase 6 beta 版本,数据库文件限制为 4Gb;对于 InterBase 6.5 和所有 Firebird 版本(1.0、1.5、2.0、2.1)为 32Tb。当数据库大小接近限制值时,必须创建附加文件。
  • 数据库工作时磁盘可用空间耗尽。
  • 对于 6.0.1.6 以下版本的 Borland InterBase 服务器–超出生成器数量限制,该限制由 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 参数即为所需的事务数量。根据 Ann W.Harrison 的说法,事务的临界数量取决于页面大小,其值如下(见表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”命令)。这是因为已确认的数据并未直接写入磁盘上的数据库文件,而是使用了操作系统(OS)的文件缓存。服务器进程向操作系统发出了数据写入命令,然后操作系统向服务器确认所有数据已保存到磁盘,但实际上数据只是存储在文件缓存中。操作系统并不急于将这些数据刷新到磁盘,因为它认为还有大量主内存可用,并将缓慢的磁盘写入操作推迟到主内存被填满之后。

2.4. 强制写入–有利有弊

为了应对这种情况,InterBase 6 提供了数据写入模式的设置。该参数称为强制写入(FW),有两种模式–ON(同步)和 OFF(异步)。FW 模式定义了 InterBase 与磁盘的通信方式。如果 FW 开启,则启用同步写入磁盘的设置,已确认的数据在 commit 命令之后立即写入磁盘,服务器等待写入完成后才继续处理。如果 FW 关闭,InterBase 在事务提交命令后不急于将数据写入磁盘,而是将此任务委托给并行线程,主线程继续处理数据而不等待写入完成。同步写入模式是最谨慎的模式之一,它能最大限度地减少可能的数据丢失,但可能会导致一定的性能损失。异步写入模式增加了大量数据丢失的概率。为了获得最大性能,通常会设置 FW Off 模式。但在断电的情况下,异步写入期间丢失的数据量远多于同步写入。在设置写入模式时,你需要权衡:百分之几的性能提升是否比意外断电时数小时的工作成果更重要。

用户常常对 InterBase 不够重视。小型组织在任何小事上都要节省,往往在计算机服务器上同时安装了 DBMS 服务器和各种服务器程序(而且不仅仅是服务器程序)。如果系统挂起,人们不会多想就按下 RESET 键(这种情况一天可能发生好几次)。尽管与其他 DBMS 相比,InterBase 对此类操作非常稳定,并且允许在紧急重启后立即开始使用数据库,但这种使用方式并不理想。孤立页面的数量会增加,数据之间的连接也会因故障重启而丢失。

这种情况可能会持续很长时间,但迟早会走到尽头。当损坏的页面出现在 PIP 或生成器页面中,或者数据库头页损坏时,数据库可能永远无法再次打开,变成一大堆无法从中提取任何有用信息字节的零散数据。

2.5. 硬盘损坏

硬盘损坏会导致数据库重要系统页面的缺失和/或剩余页面之间链接的损坏。此类损坏是最难处理的情况之一,因为几乎总是需要底层干预才能恢复数据库。

2.6. 数据库设计错误

你需要了解数据库开发人员所犯的一些错误,这些错误可能导致无法从备份副本(由 gbak 程序创建的 *.gbk 文件)恢复数据库。首先是在数据库级别上对约束的粗心使用。典型例子是 NOT NULL 约束。假设我们有一个已填充了若干记录的表。现在我们使用 ALTER TABLE 命令向该表添加一列,并指定该列不能包含未定义值 NULL。类似这样:

ALTER TABLE sometable Field/INTEGER NOT NULL

在这种情况下,不会出现人们可能预期的服务器错误。此元数据修改将被提交,我们不会收到任何错误或警告消息,这造成了一种一切正常的假象。

然而,如果我们备份数据库并尝试从备份副本恢复,在恢复阶段会收到错误消息(因为 Null 被插入到具有 NOT NULL 约束的列中),恢复过程将被中断。(Craig Stuntz 提供的重要说明–从 InterBase 7.1 版本开始,恢复时默认忽略约束(可以通过命令行开关控制),几乎任何未损坏的备份都可以恢复。在备份后进行测试恢复始终是个好主意,但这个问题在 7.1 版本中应该基本消失了。)此备份副本无法恢复。如果恢复的目标文件与现有数据库同名(在恢复过程中现有数据库工作文件被覆盖),我们将丢失全部信息。

这与 NOT NULL 约束是通过系统触发器实现的有关,这些触发器只检查到达的数据。在从备份副本恢复数据时,数据被插入到刚创建的空表中–此时我们会在具有 NOT NULL 约束的列中发现不允许的 NULL 值。

一些开发人员认为 InterBase 的这种行为是不正确的,但另一种做法将无法向数据库表添加带有 NOT NULL 限制的字段。

关于默认值以及在创建时用默认值填充的问题,Firebird 架构师们进行了广泛讨论,但未被采纳,因为程序员显然打算根据算法来填充它,而该算法相当复杂且可能是迭代的。但无法保证他能否区分前一次迭代忽略的记录和未填充的记录。

类似的问题也可能由垃圾回收故障引起,原因包括连接时设置了不正确的数据库路径(损坏原因 3)以及服务器正在使用数据库时对数据库文件的文件访问(损坏原因 4),某些表中可能会出现完全填充 Null 的记录。这些记录很难检测,因为它们不符合完整性控制限制,Select 操作符根本看不到它们,尽管它们会进入备份副本。如果因此无法恢复,应该运行 gfix 程序(见下文),使用非索引字段作为搜索条件查找并删除这些记录,然后重试制作备份副本并从中恢复数据库。总之,数据库损坏的原因有很多,你应该始终做好最坏的准备–你的数据库可能因这样或那样的原因而损坏。你还必须准备好恢复和保存有价值的信息。现在我们来考虑保证 InterBase 数据库安全的预防措施,以及修复损坏数据库的方法。

2.7. InterBase 数据库损坏的预防措施

为了防止数据库损坏,应该始终创建备份副本(如果你想了解更多关于备份的信息,请参阅“备份与恢复”章节)。这是防止数据库损坏最可靠的方法。只有备份才能 100% 保证数据库安全。如上所述,备份的结果可能是一个无用的副本(无法恢复的副本),因此从副本恢复数据库时不能覆盖原有脚本,备份必须按照明确的规则执行。首先,备份必须尽可能频繁地执行;其次,备份必须是连续的;第三,必须检查备份副本的可恢复性。

通常,备份意味着需要相当频繁地制作备份副本,例如每二十四小时一次。数据库备份之间的数据周期越短,故障导致的数据丢失就越少。备份的连续性意味着备份数量必须增加,并且至少保存一周。如果有可能,应该将备份写入专用设备(如磁带机),如果没有可能,则将其复制到另一台计算机。备份副本的历史记录将有助于发现隐藏的损坏,并应对很久以前产生但意外显现的错误。必须检查所获得的备份是否能够无错误地恢复。只有一种方法可以检查–通过测试恢复过程。应该说,恢复过程所需的时间是备份的 3 倍,对于大型数据库来说,每天执行恢复验证是很困难的,因为这可能会中断用户数小时的工作(夜间休息时间可能不够)。

如果大型组织不在“火柴”上节省,并为此目的留一台计算机,那会更好。

在这种情况下,如果服务器必须每周7天、每天24小时承受严重负载,我们可以使用SHADOW机制从数据库获取快照,并从即时副本执行进一步的备份操作。备份过程和数据库恢复在“备份与恢复”一章中有详细描述。在创建备份然后从中恢复数据库时,数据库中所有数据都会被重新创建。这个过程(备份/恢复或b/r)有助于纠正数据库中大多数非致命错误,这些错误与硬盘损坏、检测数据库完整性问题、清理数据库中的垃圾(旧版本和记录片段、不完整事务)有关,并显著减小数据库大小。

定期b/r是InterBase数据库安全的保障。如果数据库正在运行,建议每周执行一次b/r。说实话,有一些关于InterBase数据库多年密集使用而未进行备份/恢复的实例。

然而,为了安全起见,最好执行此过程,尤其是因为它可以轻松自动化(参见“备份”一章)。

如果由于某些原因无法经常执行备份/恢复,那么可以使用gfix工具来检查和恢复数据库。gfix允许在不进行b/r的情况下检查和移除许多错误。

2.8. 命令行工具gfix

命令行工具gfix用于检查和恢复数据库。此外,gfix还可以执行各种数据库控制活动:更改数据库方言、设置和取消“只读”模式、为具体数据库设置缓存大小,以及一些重要功能(您可以在InterBase 6操作指南[4.)中了解它们)。gfix以命令行模式运行,具有以下语法:

Gfix [ options] db name

Options - 是用于执行gfix的一组选项,db name是要对其执行由选项集定义的操作的数据库名称。表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)。当然,通过任何GUI设置各种检查和恢复过程的选项更方便,但我们将考虑使用命令行工具进行数据库恢复的功能。这些工具包含在InterBase中,您可以确信它们在所有运行InterBase的操作系统上的行为都是相同的。它们始终在身边是非常重要的。

此外,允许从客户端计算机执行数据库管理的现有工具使用Services API,而InterBase服务器Classic架构不支持该API。这意味着您可以在SuperServer服务器架构下使用第三方产品。

2.9. 修复损坏的数据库

假设我们的数据库中存在一些错误。首先,我们必须检查这些错误是否存在;其次,我们必须尝试纠正这些错误。您应遵循以下说明。

如果InterBase服务器仍在运行,您应该停止它,并制作文件或数据库文件的副本。所有恢复活动应仅对数据库副本执行,因为所选方法可能导致不幸的结果,您将不得不(从头开始)重新启动恢复过程。创建副本后,我们将执行整个数据库验证(检查记录片段)。

我们应为此执行以下命令:

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

在这种情况下,corruptbase.gdb - 是损坏数据库的副本。命令将

检查数据库是否存在任何结构损坏,并给出未解决问题的列表。如果检测到此类错误,我们将不得不删除损坏的数据,并使用以下命令为备份/恢复做好准备:

gfix -mend -user SYSDBA -password your_masterkey corruptbase gdb

执行命令后,您应该检查数据库中是否还有错误。您必须使用选项-v -full运行gfix,当过程结束后,执行数据库备份:

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* FROM 表 N。如果正常执行,你可以将获得的数据保存到外部源中。最好将数据存储在脚本中(几乎所有 GUI 都提供此功能),除非表中包含 BLOB 字段。如果表中有 BLOB 字段,那么其中的数据应该由充当中介角色的客户端程序保存到另一个数据库中。也许你必须专门为数据恢复目的编写这个简单的程序。
  • 如果你未能检索到所有数据,应该删除所有索引并重试。实际上,可以从恢复一开始就删除所有表中的索引,因为不再需要它们了。当然,如果你没有与损坏数据库相同的元数据结构,则有必要记录你对损坏的源数据库执行的所有操作。
  • 如果在删除索引后仍无法从表中读取所有数据,可以尝试按主键进行范围查询。这意味着选择特定的数据范围。例如:

SELECT * FROM 表 N WHERE field_PK >=0 AND field_PK <=10000

这里的 Field_PK 是主键。InterBase 采用页式数据组织,因此值的范围查询可能相当有效,尽管看起来有点像巫术。尽管如此,它是有效的,因为我们可以将数据从损坏页面的查询中排除,并幸运地读取其他页面。你可以回想我们的论点:SQL 中没有定义记录存储的顺序。确实,没有人保证未排序的查询在重启后会以相同的顺序返回记录,但物理记录在数据库内部确实以确定的内部顺序存储。显然,服务器不会仅仅为了遵守 SQL 标准而打乱记录。你可以尝试利用这种内部顺序从损坏的数据库中提取数据(如果你想了解更多关于数据页及其关联的信息,请参阅“InterBase 数据库结构”一章)。

Vitaliy Barmin,一位经验丰富的俄罗斯 InterBase 开发人员报告说,通过这种方式,他成功地从不可恢复的数据库中恢复了高达 98% 的信息(其中有大量损坏的页面)。因此,损坏数据库中的数据必须转移到新数据库或外部源(如 SQL 脚本)中。复制数据时,请注意损坏数据库中的生成器值(必须保存它们,以便在新数据库中重新开始正常工作)。如果你没有完整的元数据副本,应该提取存储过程、触发器、约束和索引定义的文本。

2.11. 无望数据库的恢复

总的来说,数据库恢复可能非常麻烦和困难,因此最好制作数据库的备份副本,而不是恢复损坏的数据,无论发生什么,你都不应该绝望,因为在最困难的情况下也能找到解决方案。现在我们来考虑两种情况。

第一种情况(经典问题)。一个无法恢复的备份,因为带有 NOT NULL 约束的列中存在 NULL 值(恢复过程是在工作文件上运行的)。工作文件被删除了,恢复过程因错误而中断。由于轻率的操作,我们得到了一大堆无用的数据(无法恢复),而不是备份副本。但解决方案找到了。程序员设法回忆起哪个表和哪个列有 NOT NULL 约束。备份文件被加载到十六进制编辑器中。通过搜索,在那里找到了与该列定义相对应的字节组合。经过无数次实验,发现 NOT NULL 约束在列名附近某处添加了 1。在 HEX 编辑器中,这个“1”被改为“0”,备份副本就恢复了。在那之后,程序员一劳永逸地记住了如何执行备份过程和恢复。

第二种情况。情况是灾难性的。数据库在扩展阶段因磁盘空间不足而损坏。当增加数据库大小时,服务器会创建一系列至关重要的页面(例如,事务清单页面和页面清单页面,RDB$Pages 关系的附加页面),并将它们写入数据库末尾。结果,数据库既无法通过管理工具打开,也无法通过 GBAK 实用程序打开。当我们尝试连接数据库时,出现了错误消息(“Unexpected end of file”)。

当我们运行 gfix 实用程序时,发生了奇怪的事情:程序陷入了无限循环。当 gfix 运行时,服务器以高速(约每秒 100 Kb)向日志(InterBase 日志文件)写入错误。结果,日志文件很快填满了所有可用磁盘空间。我们甚至不得不编写一个程序,按定时器删除这个日志。这个过程持续了很长时间–gfix 运行了超过 16 个小时,没有任何结果。日志中充满了以下形式的错误:“Page XXX doubly allocated”。在 InterBase 起始源代码(文件 val.#)中,有这个错误的简短描述。它说当同一个数据页被使用两次时会出现此错误。显然,这个错误是至关重要页面损坏的结果。

结果,经过几天不幸的实验,以标准方式恢复数据的尝试被放弃了。因此,我们不得不使用对损坏数据库中存储的数据进行低级分析的方法。

Alexander Kozelskiy,East View Publications Inc 信息技术部门负责人,提出了如何从类似的不可恢复数据库中提取信息的想法。

我们通过研究得到的恢复方法基于这样一个事实:数据库具有页式组织,每个表的数据都收集在数据页中。每个数据页都包含它所存储数据的表的标识符。恢复几个关键表中的数据尤为重要。我们有来自相似表的数据,这些数据来自一个运行良好的旧备份副本,可以作为模式。将模式数据库加载到十六进制源编辑器中,然后搜索我们感兴趣的那些数据的模式。这些数据以十六进制格式复制到缓冲区,然后将损坏数据库的剩余部分加载到编辑器中。在损坏的数据库中找到了与模式相对应的字节序列,并分析了(找到该序列的)页面。

首先我们确定了页面的起始位置,但这并不困难,因为数据库文件的大小可以被数据页大小整除。当前字节数除以页大小–8192 字节,将结果近似为整数(得到当前页号)。然后将当前页号乘以页大小,得到与当前页起始位置相对应的字节号。分析头部后,我们确定了页面类型(对于带数据的页面,类型为 5–参见起始 InterBase 源代码集中的 ods.h 文件,以及“InterBase 数据库结构”一章)以及所需表的标识符。

然后编写了一个程序,对整个数据库进行分析,将所需表的所有页面收集到一个连续块中,并将其移动到文件中。

这样,当我们首先获得了所需的数据后,便开始分析所选页面的内容。InterBase广泛使用数据压缩来节省空间。例如,一个包含“ABC”字符串的VARCHAR类型,它存储以下值的序列:字符串长度(2字节),在我们的例子中是0003,然后是符号本身,再然后是校验和。我们必须编写字符串分析器以及其他数据库类型的分析器,将数据从十六进制格式转换为普通视图。通过使用“手动”方法分析数据库内容,我们成功地从几个关键表中提取了高达80%的信息。后来,在经验的基础上,Oleg Kulkov和本书作者之一Alexey Kovyazin开发了InterBase Surgeon实用程序,该程序直接访问数据库,绕过InterBase引擎,允许以正确的方式直接读取和解释InterBase数据库中的数据。

使用InterBase Surgeon,我们能够检测损坏的原因,并恢复高达90%的完全无法恢复的数据库–这些数据库无法被InterBase打开,也无法通过标准方法恢复。

您可以从程序官方网站www.ib-aid.com下载此程序。

3. 致谢

我要向所有帮助我创建本指南的人致以感谢:

Craig Stuntz、Alexander Nevsky、Konstantin Sipachev、Tatjana Sipacheva以及InterBase和Firebird社区中所有其他善良且知识渊博的人。

如果您对本章有任何建议或问题,请随时发送电子邮件。

© 2002 Alexey Kovyazin, Serge Vostrikov。

版权所有 © 2004 IBSurgeon团队。保留所有权利。