前几天有个朋友半夜给我打电话,声音里带着点急:“兄弟,数据库卡在‘正在还原’了,前台系统全停了,咋整?”这事儿我太熟了。搞过SQL Server的都知道,数据库状态跳成“正在还原”,就像你电脑开机卡在logo界面不动弹,看着就让人头皮发麻。更可气的是,有时候这状态还真不是啥大事,操作不对反而越搞越糟。今天咱就把这事儿掰开揉碎了聊聊,三招下来,保证你以后遇到这种情况,心里有底,手上有活。

先说说“正在还原”这状态到底啥意思。数据库在SQL Server里有个状态机,正常跑的时候是“在线”,你执行RESTORE命令时,它会切到“正在还原”来等你后续操作。如果你只跑了一个RESTORE DATABASE ... FROM DISK,没加WITH RECOVERY或者WITH NORECOVERY,那数据库就会卡在这儿。还有一种常见情况,是别人做日志备份还原时没处理好,或者你手动操作时漏了参数。别慌,这状态不是硬件坏了,也不是数据丢了,只是SQL Server在等你下个指令。搞清楚这个,你才能对症下药。
第一招,也是最快的一招——直接执行RESTORE DATABASE WITH RECOVERY。这招适合你确定所有备份都已经还原完毕,数据库可以上线的情况。打开SSMS,连接到对应实例,跑一句:RESTORE DATABASE [你的数据库名] WITH RECOVERY。就这么简单。执行完以后,数据库会从“正在还原”切回“在线”。注意一个小坑:如果这个数据库之前用的是NORECOVERY模式做还原,那你必须确认没有后续备份需要应用,否则数据会丢失。我见过有人不管三七二十一直接跑这句,结果发现还有未应用的日志备份,数据少了好几天的,那就得从头再来。所以用这招前,先问问自己:所有备份都还原了吗?
第二招,适合你不太确定当前还原链的情况——查系统视图,理清还原状态。打开SSMS,连到实例,跑这句:SELECT sessionid, command, percentcomplete, estimatedcompletiontime FROM sys.dmexecrequests WHERE command LIKE ‘RESTORE%’。这个视图会告诉你当前有没有正在跑的还原任务。如果没有,再看数据库状态:SELECT name, statedesc FROM sys.databases WHERE name = ‘你的数据库名’。如果statedesc是RESTORING,那说明数据库确实卡在这儿了。这时候你可以用RESTORE DATABASE [你的数据库名] WITH RECOVERY来推它一把,但保险起见,先查一下还原历史:SELECT destinationdatabasename, restoredate, restoretype, replace FROM msdb.dbo.restorehistory WHERE destinationdatabasename = ‘你的数据库名’。这段历史能告诉你最近一次还原是什么时候、什么类型。如果是完整还原且没带RECOVERY,那直接跑第一招就行。如果中间有差异备份或日志备份,你得先补全这些备份,再跑RECOVERY。
第三招,是遇到顽固情况时的杀手锏——杀掉后台进程,强制恢复。有时候你跑了RESTORE WITH RECOVERY,但数据库还是卡在“正在还原”,那可能是某个后台会话占着资源不放。先查一下:SELECT sessionid, blockingsessionid, waittype, waittime FROM sys.dmexecrequests WHERE command LIKE ‘RESTORE%’。如果找到阻塞的会话,用KILL [sessionid]来结束它。注意,KILL命令要小心,别误杀了系统进程。杀掉以后,再执行RESTORE DATABASE [你的数据库名] WITH RECOVERY。如果还不行,那就得用终极手段:把数据库脱机再联机。跑这句:ALTER DATABASE [你的数据库名] SET OFFLINE WITH ROLLBACK IMMEDIATE,然后马上ALTER DATABASE [你的数据库名] SET ONLINE。这招会强制回滚所有未完成的事务,把数据库状态重置。但代价是:如果有未提交的日志,数据可能会丢失一部分。所以生产环境用这招前,最好先和业务方确认一下,能接受多少数据损失。
别以为这三招就万事大吉了,实际操作中还有几个坑得绕开。第一个坑是权限问题。RESTORE命令需要sysadmin或dbcreator角色,普通用户跑不了。如果你连上SSMS发现执行报错“权限不足”,那先找DBA或管理员提升权限。第二个坑是文件路径。如果你还原时指定了不同的数据文件路径,SQL Server会报错。解决方案是先用RESTORE FILELISTONLY FROM DISK = ‘备份文件路径’查一下文件逻辑名和物理路径,然后用WITH MOVE子句重定向。第三个坑是还原链断裂。如果你做了完整还原后,又做了差异还原,但中间有日志备份没应用,那数据库状态会卡住。这时候你得按顺序把所有日志备份都还原一遍,再跑RECOVERY。我有个客户就因为少还原了一个日志备份,数据库卡了三天,逐条排查才搞定。
说到底,SQL Server的设计逻辑其实挺人性化的。它用“正在还原”状态来保护数据完整性,不让你在备份链不完整的情况下直接上线数据库。这就像你装修房子,工人跟你说“油漆还没干”,你非要进去踩一脚,结果就是地板花了。所以遇到这状态,别急着骂微软,先想想是不是自己操作没到位。三招下来,第一招是快刀斩乱麻,第二招是精准定位,第三招是强制干预。根据你的业务场景选一个,大多数情况五分钟内就能解决问题。
送你一句我做了这么多年数据库的感悟:备份还原这事儿,七分靠操作,三分靠心态。遇到“正在还原”别慌,先深呼吸,然后按我上面说的步骤来。如果实在搞不定,那就找台测试机还原一次,看看效果再上生产。毕竟数据安全第一,宁可多花十分钟测试,也别在线上瞎折腾。好了,今天先聊到这儿,下次有空再讲讲数据库死锁的那些破事儿。


