“无法提交索引”或如何从部分恢复(不一致)的数据库中抽取数据
Alexey Kovyazin,最后更新于2014年3月30日
修复损坏后,在还原步骤中经常会出现“Cannot commit index”错误。在Firebird 2.0及更高版本中,这只是一个警告,数据库将不会上线;而在Firebird 1.0-1.5和InterBase中,这是一个非常令人不快的错误,会停止还原过程(在200GB数据库还原结束时看到这个错误确实令人印象深刻)。
“Cannot commit index..”错误的原因很明显:损坏影响了数据库的引用完整性,记录以(从服务器角度来看)神奇的方式消失。
例如,您有一个“Customers”表和一个通过外键关联的“Orders”表。在没有损坏的情况下,不可能违反外键约束,也不可能在不先删除与该客户相关的所有订单的情况下从Customers表中删除记录。损坏会在底层影响数据库文件并直接删除记录。服务器看到外键记录中存在指向主记录未解析的链接,这真是一个“惊喜”。
这里我需要补充一个关于还原过程的提示:引擎会先还原所有表(索引未激活),这样填充表记录会快得多,然后逐个激活(即构建)索引。这意味着当还原过程开始创建索引时,所有数据已经在数据库中了,此时您会看到“Cannot commit index..”错误。
当您看到“Cannot commit index”错误时,第一个想法通常是删除相应的外键约束以允许还原完成。问题是,对于不一致但成功还原的数据库,我们该怎么办:删除的外键可能是业务逻辑的重要组成部分。
这里有2种方法:重新创建丢失的数据或删除不一致的数据。让我们看看这在上述Customers-Orders示例中意味着什么。
重新创建丢失的数据
如果您决定需要为不一致的Orders重新创建丢失的Customers,那么您需要确定丢失的ID。通常我会使用这样的SQL查询(我认为很容易根据实际情况进行调整):
SELECT O.Customer_ID FROM ORDERS O WHERE NOT EXISTS ( SELECT C.Customer_ID FROM CUSTOMERS C WHERE O.Customer_ID=C.Customer_ID)
之后,您可以手动插入带有丢失主键列表的记录,然后再次运行备份/还原。
抽取一致的数据
如果您认为丢失不一致的记录是可以接受的,您可以使用以下方法将所有数据从部分还原的数据库抽取到空数据库中,并跳过不一致的记录:
-
下载免费工具IBDataPump http://www.clevercomponents.com/demo/datapump/IBPump.zip
-
使用以下命令从修复后的数据库(经过IBFirstAID处理后)的备份中仅创建元数据数据库:
gbak -c -m -user SYSDBA -pass masterkey Disk:\Path\backup.fbk Disk:\Path\fresh.fdb
-
运行IBDataPump,将部分修复的数据库设置为源,将新的空数据库设置为目标
-
点击下一个选项卡,点击相应的按钮,在第3个选项卡中点击“Pump”。等待完成(这可能是一个漫长的过程,您可以通过检查目标数据库大小的增长动态来了解进度)。
-
结果您将获得一个具有一致外键关系的fresh.fdb数据库–这完全没问题。
如果数据库存在外键循环,IBDataPump会警告您并给出此类约束的列表–在抽取可用之前,需要删除其中一个或多个约束。
当然,有些情况下抽取需要特殊处理,如果您遇到这种情况,请联系我们的支持。