简介:这份资源面向SQL Server数据库管理员与运维开发人员,聚焦备份、还原与数据修复三大核心场景,帮助应对数据丢失、MDF文件损坏及勒索病毒加密等突发状况。包内共1个docx文档,约660KB,以图文步骤形式梳理了手动单次备份、维护计划向导自动化备份、数据库还原流程,以及PhotoRec恢复误删数据、Data Numen SQL Recovery修复损坏MDF文件等实用方法,内容紧凑、查阅方便。目前已有717人学习下载,适合希望系统掌握SQL Server数据安全保障思路、快速定位恢复方案的初中级从业者参考,也可作为日常运维排错时的速查手册。
1. SQL Server 备份还原修复:一次误删数据后的三小时抢救复盘
凌晨两点,业务库一张核心订单表被误执行了DELETE,没有WHERE。开发第一反应是找 DBA 要备份,结果发现这台 SQL Server 的维护计划里只有一次全量备份,还是三天前的,事务日志从来没做过备份。三天数据,靠日志也补不回来,最后只能从另一台只读从库拼凑,业务方对账对了整整一周。
这件事之后我把这套「备份 + 还原 + 修复」的链路重新梳理了一遍。它解决的不是「怎么点一下备份按钮」,而是三件事:备份策略怎么设计才敢还原、还原时选全量还是日志、数据库已经坏了(页损坏、误删、文件丢失)时怎么把损失压到最小。适合正在管 SQL Server 的运维、后端和兼职 DBA,尤其是那种「有备份但从没验证过能不能还原」的环境。下面按我实际落地的顺序讲,从策略到命令到踩坑。
2. 备份策略怎么定:全量、差异、日志三种备份的取舍
2.1 恢复模型决定了你能还原到什么程度
很多人上来就问「多久做一次全量」,其实顺序反了。先定恢复模型(Recovery Model),它直接决定你能不能做日志备份、能不能还原到某个时间点。
SQL Server 有三种恢复模型:
| 恢复模型 | 日志备份 | 时间点还原 | 适用场景 |
|---|---|---|---|
| 完整(FULL) | 支持 | 支持 | 核心业务库,不能丢数据 |
| 大容量日志(BULK_LOGGED) | 支持 | 部分受限 | 大批量导入期间临时切换 |
| 简单(SIMPLE) | 不支持 | 不支持 | 测试库、日志不重要的库 |
核心库必须是 FULL。切到 FULL 之后,日志会一直增长,直到你做第一次完整备份,日志空间才会被标记为可复用。这一点新手最容易翻车:切了 FULL 没做全量备份,日志文件几小时撑爆磁盘。
-- 查看当前恢复模型 SELECT name, recovery_model_desc, log_reuse_wait_desc FROM sys.databases WHERE name = 'YourDB'; -- 切换到完整恢复模型 ALTER DATABASE YourDB SET RECOVERY FULL; -- 切换后必须立刻做一次完整备份,否则日志无法截断 BACKUP DATABASE YourDB TO DISK = 'D:\Backup\YourDB_FULL_20240101.bak' WITH INIT, COMPRESSION, CHECKSUM, STATS = 10;WITH后面几个参数值得说清楚:INIT表示覆盖同名备份集,不加会追加导致文件越来越大;COMPRESSION压缩备份,CPU 换空间,一般能压到 20%~30%;CHECKSUM写入校验和,还原时能提前发现备份文件损坏,这个参数我强烈建议默认加上;STATS = 10每 10% 打印进度,长备份时心里有底。
2.2 全量 + 差异 + 日志的经典组合
单靠全量,备份窗口和恢复点目标(RPO)很难同时满足。常见做法是:
- 每周日一次全量
- 每天一次差异备份
- 每 15 分钟或 30 分钟一次日志备份
差异备份只记录上次全量以来的变化,比全量小得多;日志备份记录所有事务,能支撑时间点还原。还原时的顺序是:最近一次全量 → 最近一次差异 → 差异之后的所有日志,一个都不能少。
-- 差异备份 BACKUP DATABASE YourDB TO DISK = 'D:\Backup\YourDB_DIFF_20240101.bak' WITH INIT, COMPRESSION, CHECKSUM, DIFFERENTIAL, STATS = 10; -- 日志备份(注意不能用 INIT 覆盖,日志备份要连续) BACKUP LOG YourDB TO DISK = 'D:\Backup\YourDB_LOG_20240101_1200.trn' WITH COMPRESSION, CHECKSUM, STATS = 10;日志备份链一旦断掉(比如中间某个 .trn 文件被删、磁盘写满导致备份失败),后面的日志备份就接不上了,时间点还原只能恢复到断链之前。所以日志备份文件要单独规划保留策略,别和全量放一个目录一起被清理脚本误删。
2.3 备份文件放哪:异地备份不是可选项
备份和数据库放同一块物理磁盘,等于没备份。磁盘挂了两个一起没。我一般分三层:
- 本地快速恢复层:同机房另一台存储,保留 3~7 天,用于快速还原
- 同城异地层:同城另一个机房,保留 30 天
- 归档层:对象存储或磁带,保留按合规要求
异地备份的传输可以用BACKUP ... TO URL直接写云存储,也可以本地备份完再同步。注意TO URL需要先创建凭据(Credential),这一步在 SQL Server 2016 以后才比较顺,老版本折腾起来比较费劲。
提示:备份策略定完,一定要做一次「还原演练」。没验证过的备份,等于没有备份。我见过太多备份文件在还原时报「媒体集有 2 个媒体簇,但只提供了 1 个」这种低级错误。
3. 还原怎么做:从完整还原到时间点还原的命令拆解
3.1 完整还原与 WITH REPLACE 的坑
最基础的还原是把一个全量备份盖回去。但直接RESTORE DATABASE经常报错,因为目标库还存在、文件路径对不上。
-- 先看备份文件里有什么,别急着还原 RESTORE FILELISTONLY FROM DISK = 'D:\Backup\YourDB_FULL_20240101.bak'; -- 看备份集信息(第几个备份集、类型、时间) RESTORE HEADERONLY FROM DISK = 'D:\Backup\YourDB_FULL_20240101.bak'; -- 完整还原,覆盖现有库,并移动文件到新路径 RESTORE DATABASE YourDB FROM DISK = 'D:\Backup\YourDB_FULL_20240101.bak' WITH REPLACE, RECOVERY, MOVE 'YourDB' TO 'D:\Data\YourDB.mdf', MOVE 'YourDB_log' TO 'D:\Log\YourDB_log.ldf', STATS = 10;RESTORE FILELISTONLY返回的逻辑文件名,就是MOVE里要写的名字,写错了会报「无法覆盖文件」。REPLACE允许覆盖同名数据库,不加的话如果库已存在会直接拒绝。RECOVERY表示还原后数据库可用;如果后面还要接着还原差异或日志,这里必须写NORECOVERY,否则日志链就断了,这是还原失败最常见的原因之一。
3.2 时间点还原:把误删挡在某个时刻之前
回到开头那个误删场景,如果日志备份齐全,是可以还原到误删前一秒的。
-- 第一步:还原最近一次全量,保持 NORECOVERY RESTORE DATABASE YourDB FROM DISK = 'D:\Backup\YourDB_FULL_20240101.bak' WITH NORECOVERY, REPLACE, MOVE 'YourDB' TO 'D:\Data\YourDB.mdf', MOVE 'YourDB_log' TO 'D:\Log\YourDB_log.ldf'; -- 第二步:还原差异(如果有),仍然 NORECOVERY RESTORE DATABASE YourDB FROM DISK = 'D:\Backup\YourDB_DIFF_20240101.bak' WITH NORECOVERY; -- 第三步:还原日志到误删前的时刻 RESTORE LOG YourDB FROM DISK = 'D:\Backup\YourDB_LOG_20240101_1200.trn' WITH NORECOVERY, STOPAT = '2024-01-01T11:59:00'; -- 第四步:恢复数据库可用 RESTORE DATABASE YourDB WITH RECOVERY;STOPAT是时间点还原的核心,它把日志重放到指定时刻就停。注意STOPAT的时间是数据库服务器本地时间,不是客户端时间,跨时区环境要换算。另外如果误操作是TRUNCATE TABLE或DROP TABLE,日志里记录的操作类型不同,STOPAT依然有效,但要在还原后立刻把数据导出,别在原库上继续操作。
3.3 页面级还原:只修坏页,不动整库
如果只是某个数据页损坏(比如磁盘坏道),整库还原代价太大。SQL Server 支持页面级还原,前提是有完整备份和日志备份。
-- 检查数据库是否有页损坏 DBCC CHECKDB('YourDB') WITH NO_INFOMSGS; -- 从完整备份还原指定页面 RESTORE DATABASE YourDB PAGE = '1:456' FROM DISK = 'D:\Backup\YourDB_FULL_20240101.bak' WITH NORECOVERY; -- 再用日志备份前滚 RESTORE LOG YourDB FROM DISK = 'D:\Backup\YourDB_LOG_20240101_1200.trn' WITH RECOVERY;PAGE = '1:456'里的1是文件 ID,456是页号,DBCC CHECKDB会直接告诉你坏页的 file:page。页面级还原要求数据库处于完整恢复模型,且日志链完整,否则前滚不了。
4. 数据库坏了怎么修:DBCC CHECKDB 与紧急模式
4.1 先判断损坏程度,别急着修
数据库报「可疑」或者查询报「页校验和错误」时,第一步不是修,是评估。
-- 查看数据库状态 SELECT name, state_desc, user_access_desc FROM sys.databases WHERE name = 'YourDB'; -- 只读方式检查,不锁库太久 DBCC CHECKDB('YourDB') WITH NO_INFOMSGS, ALL_ERRORMSGS;DBCC CHECKDB会返回错误列表,常见的有:
- 页校验和失败(checksum mismatch):物理损坏,优先从备份还原
- 索引不一致:逻辑损坏,可以
DBCC CHECKDB ... REPAIR_REBUILD重建索引 - 分配错误:页归属混乱,修复风险高
4.2 紧急模式下的数据抢救
如果备份不可用,数据库又起不来,可以进紧急模式(EMERGENCY)把数据导出来。
-- 单用户模式进紧急状态 ALTER DATABASE YourDB SET EMERGENCY; ALTER DATABASE YourDB SET SINGLE_USER; DBCC CHECKDB('YourDB', REPAIR_ALLOW_DATA_LOSS); -- 抢救完切回多用户 ALTER DATABASE YourDB SET MULTI_USER;REPAIR_ALLOW_DATA_LOSS这个名字就是警告:它会删掉损坏的页来让数据库可用,被删的数据就没了。所以这一步之前,能复制一份 .mdf/.ldf 就复制一份,留个后悔药。修复完立刻做完整备份,然后DBCC CHECKDB再确认一遍。
4.3 日志文件损坏与误删的应对
日志文件(.ldf)损坏或丢失,数据库可能无法附加。如果数据库正常关闭过、且没有未提交事务,可以尝试用ATTACH_REBUILD_LOG重建日志。
-- 重建日志(仅限干净关闭的库) CREATE DATABASE YourDB ON (FILENAME = 'D:\Data\YourDB.mdf') FOR ATTACH_REBUILD_LOG;这个命令会新建一个日志文件,但前提是数据文件是干净的。如果数据文件本身也不一致,重建会失败,只能从备份还原。所以日志文件千万别随手删,它不是可有可无的。
5. 避坑与排查:还原修复中最容易翻车的五件事
5.1 还原报「媒体集有 2 个媒体簇,但只提供了 1 个」
现象:RESTORE时报媒体集不匹配,明明备份文件就在那。
原因:备份时用了多个TO DISK或多个备份设备,还原时只给了一个文件。或者备份文件被分卷(striped backup),少给了分卷。
解决:用RESTORE HEADERONLY看FamilyCount,如果是 2,说明备份跨了两个文件,还原时要把所有分卷都列上。日常备份尽量单文件,除非文件大到需要分卷。
5.2 日志链断了,时间点还原只能到断点
现象:还原日志时报「此日志备份无法应用,因为数据库未处于还原状态」或「日志链中断」。
原因:中间某个日志备份丢失、失败,或者有人对数据库做了BACKUP LOG ... WITH NO_LOG/TRUNCATE_ONLY(老版本),把日志截断了。
解决:只能还原到断链前最后一个可用日志。预防办法是日志备份任务加告警,失败立刻处理,别等到要还原时才发现。
5.3 还原后数据库变成「正在还原」状态
现象:还原完数据库显示「正在还原(Restoring)」,无法访问。
原因:还原时用了NORECOVERY,但后面忘了执行RESTORE DATABASE ... WITH RECOVERY。
解决:执行RESTORE DATABASE YourDB WITH RECOVERY;即可。如果还有日志要还原,就继续NORECOVERY,全部还原完再RECOVERY。
5.4 磁盘空间不足导致还原中途失败
现象:还原到一半报「磁盘空间不足」,数据库卡在还原状态。
原因:还原需要同时容纳原库文件和新还原的文件,空间需求是数据文件大小的 1.5~2 倍。压缩备份还原时还要额外临时空间。
解决:还原前用RESTORE FILELISTONLY看文件大小,预留足够空间。空间不够时可以先删掉原库文件(确认备份可用后),或者还原到另一块盘再迁移。
5.5 DBCC CHECKDB 修复后数据对不上
现象:REPAIR_ALLOW_DATA_LOSS修复后,某些表行数变少或查询报错。
原因:修复过程删除了损坏页,页上的数据永久丢失。
解决:修复前尽量导出可读数据,修复后立刻全量备份,然后和业务方核对关键表。能不用ALLOW_DATA_LOSS就不用,优先从备份还原。
6. 把还原演练做成例行任务:一个可复用的验证脚本
备份策略写得再漂亮,不验证都是纸上谈兵。我现在的习惯是每周自动跑一次还原演练:把生产库的最近全量 + 差异 + 日志还原到一台测试实例,跑DBCC CHECKDB,再对比几张核心表的行数。下面是一个简化版的验证脚本框架。
-- 还原演练:还原到测试库 YourDB_Verify -- 1. 还原全量 RESTORE DATABASE YourDB_Verify FROM DISK = 'D:\Backup\YourDB_FULL_latest.bak' WITH NORECOVERY, REPLACE, MOVE 'YourDB' TO 'D:\Verify\YourDB_Verify.mdf', MOVE 'YourDB_log' TO 'D:\Verify\YourDB_Verify_log.ldf'; -- 2. 还原差异 RESTORE DATABASE YourDB_Verify FROM DISK = 'D:\Backup\YourDB_DIFF_latest.bak' WITH NORECOVERY; -- 3. 还原日志(按顺序,最后一个用 RECOVERY) RESTORE LOG YourDB_Verify FROM DISK = 'D:\Backup\YourDB_LOG_latest.trn' WITH RECOVERY; -- 4. 一致性检查 DBCC CHECKDB('YourDB_Verify') WITH NO_INFOMSGS, ALL_ERRORMSGS; -- 5. 核心表行数对比(示例) SELECT 'Orders' AS TableName, COUNT(*) AS Cnt FROM YourDB_Verify.dbo.Orders UNION ALL SELECT 'Customers', COUNT(*) FROM YourDB_Verify.dbo.Customers;这个脚本的关键点:还原顺序不能乱,日志必须按备份时间顺序应用,最后一个日志还原用RECOVERY让库可用。行数对比不用追求完全一致(演练期间生产还在写),但量级要对得上,差太多说明还原链有问题。
演练频率我一般设成每周一次,核心库每天一次。演练实例可以和开发测试共用,但要注意别把生产备份还原到有敏感数据的实例上。另外演练完记得清理,别让测试库把磁盘占满。
一个血泪教训:我曾经因为备份文件放在网络共享上,演练时发现共享权限被改过,还原直接失败。后来所有备份路径都加了连通性和权限的预检。备份这件事,平时多花十分钟验证,出事时能省三天。希望帮到你。
本文还有配套的精品资源,点击获取