半夜三点,手机震了。运维小张的声音带着哭腔:“哥,数据库卡在‘正在还原’状态,业务全停了,老板在群里@我三回了……”这种情况我见得太多了。SQL Server 的“正在还原”状态,说白了就是数据库在说“我还没准备好,你别碰我”。但有时候它真的在认真干活,有时候却在装死。怎么分?怎么治?今天把几个压箱底的办法抖出来。

先说第一种情况:数据库其实在正常工作,只是你太着急了。当你执行 RESTORE 命令时,SQL Server 会把数据文件、日志文件从备份介质搬到目标位置,这个过程叫“还原”。如果备份文件很大,或者磁盘读写慢,或者网络传输有延迟,数据库就会长时间停留在“正在还原”。这时你刷新页面,它永远显示“正在还原”。别慌,先查询 sys.dmexecrequests 视图,看有没有 RESTORE 相关的请求正在运行。如果有,说明它在干活,你就等着。我记得有个客户,备份文件 200 GB,放在机械硬盘上,等了 40 分钟才完成。他们以为卡死了,差点要重启服务器。
第二种情况是还原没给“尾巴”。很多人还原数据库时,习惯使用 WITH NORECOVERY 选项。这个选项的意思是“我还要继续还原,先别让用户访问”。如果只还原了完整备份,没接着还原差异备份或日志备份,数据库就会一直卡在“正在还原”。这时需要执行 RESTORE DATABASE … WITH RECOVERY,告诉 SQL Server:“行了,就到这儿,让用户进来吧”。该命令不会做额外操作,只是把数据库状态从“正在还原”切换到“在线”。记住,如果后续还有日志要还原,千万别用 RECOVERY,必须继续使用 NORECOVERY。
第三种情况最头疼——还原过程中断导致的锁死。可能是磁盘空间不足,可能是备份文件损坏,也可能是 SQL Server 服务崩溃。此时数据库像个半死不活的人,既不能恢复,也不能删除。执行 DROP DATABASE 会报错, RESTORE WITH RECOVERY 也无效。我有个笨办法但很管用:先把数据库设为单用户模式,再执行 RESTORE DATABASE WITH RECOVERY。如果仍不行,只能使用“杀手锏”——分离数据库。执行 spdetachdb,删掉物理文件后重新附加。此招有风险,务必先做好完整备份。
有人问:“我能不能直接把数据库删了重建?”理论上可以,但代价可能很大。如果没有最近的备份,或者备份链不完整,删了就什么都没有了。我见过最惨的案例,运维人员以为“正在还原”是死锁,直接重启了 SQL Server 服务,结果数据库状态变成了“可疑”。那时连分离都做不了,只能从备份恢复,丢失了三个小时的数据。所以,千万别冲动。
还有一种情况容易被忽略:镜像或 AlwaysOn 环境下的状态同步。在数据库镜像或可用性组中,辅助副本会一直保持“正在还原”状态,因为它要持续接收主副本的日志,这是正常现象。但如果在主副本上看到“正在还原”,就说明有问题。可能是网络分区导致主副本降级,也可能是仲裁丢失。此时先检查 WSFC 集群状态,确认节点是否都在线。有时只是心跳超时,重启网络服务就能解决。
说回核心技术点。SQL Server 的“正在还原”状态,底层逻辑是数据库文件的恢复过程。每个数据库都有 LSN(日志序列号),还原过程就是按 LSN 顺序把数据写回磁盘。如果 LSN 链断了,比如跳过了某个日志备份,数据库就会卡住。这时需要找齐所有备份文件,按时间顺序逐个还原。如果实在找不全,可以使用 WITH REPLACE 强制覆盖,但这会破坏备份链,后续的日志备份将无法使用。所以,日常备份策略一定要清晰,别把备份文件乱放。
我的经验是,遇到“正在还原”先深呼吸,然后按下面的顺序排查:第一,查询 sys.dmexecrequests 看是否有活动请求;第二,查询 sys.databases 的 state_desc 字段,确认具体状态;第三,查看错误日志,是否有 I/O 错误或磁盘空间警告。90% 的问题都能在这三步里找到答案。剩下的 10% 多半是硬件故障或系统 BUG,需要联系微软支持。
说点心里话。数据库卡在“正在还原”不可怕,可怕的是你不知道它为什么卡。很多人看到“正在还原”就慌了,要么重启服务,要么删库重建,结果越搞越糟。DBA 这行,技术重要,心态更关键。你越急,数据库越跟你对着干。下次遇到这种情况,打开 SSMS,先喝口水,然后按我今天说的三招来试:查状态、补还原、强制恢复。十有八九能搞定。实在搞不定,也没关系,至少你知道下一步该找谁。


