干我们这行的,最怕半夜手机响。上周三凌晨两点,同事老张的电话就来了,声音都是抖的:“库挂了,日志文件读不出来,老板明早要报表。”我让他别慌,先把TRN文件备份出来,然后一步步教他做数据库还原。折腾到四点半,数据找回来了,老张在电话那头长舒一口气。这事让我想写点东西——TRN文件这玩意儿,看着就是个后缀名,真出问题的时候,能救命也能要命。

先说说TRN文件到底是啥。它是SQL Server的事务日志备份文件,记录着数据库每一次增删改的详细操作。数据库完整备份像拍照片,TRN文件就是连续录像,能从上次备份的点一直播到你出事那一刻。所以当你的数据库主文件损坏、误删数据、或者硬盘挂掉,光有完整备份不够,必须配合TRN文件才能把损失降到最低。但问题是,这文件特别娇气——存储介质坏道、异常断电、甚至备份过程中网络抖动,都可能让它损坏。我见过最离谱的案例,运维把TRN文件放在U盘里,结果U盘中毒,整个文件头都烂了。
遇到TRN文件报错,第一反应别是删了重来。SQL Server有个隐藏技能叫尾日志备份,能抢救出当前数据库里还没写入TRN文件的那部分日志。做法很简单,在SSMS里右键数据库,任务→备份,备份类型选“事务日志”,但关键一步在选项页——把“备份前截断事务日志”的勾去掉,同时勾上“继续写入现有备份集”。这样即使TRN文件本身损坏,你也能拿到一份新的日志备份,至少保住崩溃前几秒的数据。
如果尾日志备份也失败了,别灰心,试试用WITH CONTINUEAFTERERROR参数强制还原。正常还原命令是RESTORE DATABASE xxx FROM DISK='xxx.trn' WITH NORECOVERY,但遇到损坏文件会直接中断。加上这个参数后,SQL Server会跳过损坏的日志块,把能读的部分先还原出来。我做过实验,一个2GB的TRN文件,损坏率在15%以内,用这个参数能救回95%以上的数据。代价是还原后的数据库可能处于“质疑”状态,需要你再跑一遍DBCC CHECKDB来修复逻辑一致性。
但更头疼的情况是TRN文件整个打不开,连文件头都读不了。这时候就得用第三方工具了,市面上的ApexSQL Log、Stellar Repair for MS SQL都比较成熟。操作逻辑大同小异:选择损坏的TRN文件,工具会扫描文件内的日志记录,把每条操作解析成可读的SQL语句,然后你选择需要恢复的时间点,生成回滚脚本。我用这类工具救过一个大客户的库,他们财务系统误跑了一个批量删除,TRN文件正好覆盖了那段时间,工具直接把删除操作逆向了,生成了INSERT语句,数据原样怼了回去。
不过得泼盆冷水,所有还原手段都有前提——你得有完整的备份链。很多人只备份完整数据库,TRN文件从来没备份过,或者备份策略混乱,完整备份和日志备份之间断档,那神仙来了也救不了。我见过最典型的错误是:每天凌晨1点做完整备份,但TRN文件只保留最近一周,结果第8天数据出问题,想还原到第5天的状态,日志早被清理任务删了。所以备份策略别嫌啰嗦,完整备份+定期TRN备份+定期还原演练,三件套缺一不可。
还有个小技巧很多人不知道:还原时可以同时指定多个TRN文件。比如你有完整备份bak文件,加上三个TRN文件,一条命令就能全部恢复:RESTORE DATABASE xxx FROM DISK='xxx.bak', DISK='xxx1.trn', DISK='xxx2.trn', DISK='xxx3.trn' WITH RECOVERY。这样省得一步步还原,而且能减少中间状态出错的风险。但要注意顺序,必须按备份时间先后排列,顺序错了直接报错。
说点掏心窝子的话。数据库还原这事儿,七分靠平时功夫,三分靠临场反应。TRN文件损坏那天晚上,老张能救回来,是因为他们公司去年被我逼着做了三次还原演练,把各种坏情况都模拟过了。真到了出事儿那天,照着演练步骤走,心里不慌。如果你现在还没做过一次完整的还原测试,找个周末,拿台测试服务器,把备份和还原流程从头到尾跑一遍。等到真出事那天,你会感谢今天自己这个决定的。毕竟,数据这东西,没了就是没了,再贵的工具也变不回来。


