说明: 此次模拟删除某些数据表 , 尝试修复
前提条件:删表前有个历史完整备份、完整备份后的事务日志完整
一、准备初始数据
1.建表插入数据

-- 创建表和插入数据 CREATE TABLE Students ( StudentID INT PRIMARY KEY, Name NVARCHAR(50) NOT NULL, Age INT CHECK (Age >= 0), RegisterDate DATETIME DEFAULT GETDATE() ); -- 插入数据 INSERT INTO Students (StudentID, Name, Age, RegisterDate) VALUES (3, '王五', 21, '2023-10-02 10:30:00'), (4, '赵六', 19, '2023-10-03 14:15:00'), (5, '陈七', 23, DEFAULT); -- 使用默认值填充 RegisterDate -- 查询表 select * from Students ; 3 王五 21 2023-10-02 10:30:00.000 4 赵六 19 2023-10-03 14:15:00.000 5 陈七 23 2025-03-06 15:40:27.967
2.完备数据库
--完整备份 BACKUP DATABASE [db_test] TO DISK = 'C:\bak\dbtest1545.bak';
3.建表插入数据(15/48分)

-- 建表插入数据 CREATE TABLE Studentsnew ( StudentID INT PRIMARY KEY, Name NVARCHAR(50) NOT NULL, Age INT CHECK (Age >= 0), RegisterDate DATETIME DEFAULT GETDATE() ); -- 插入数据 INSERT INTO Studentsnew (StudentID, Name, Age, RegisterDate) VALUES (3, '王五', 21, '2023-10-02 10:30:00'), (4, '赵六', 19, '2023-10-03 14:15:00'), (5, '陈七', 23, DEFAULT); -- 使用默认值填充 RegisterDate -- 查询表 select * from Studentsnew
4.删表(15/51分)
drop table Studentsnew;
drop table Students;
5.建表插入数据(15/53分)

-- 建表插入数据 CREATE TABLE Studentsnew2 ( StudentID INT PRIMARY KEY, Name NVARCHAR(50) NOT NULL, Age INT CHECK (Age >= 0), RegisterDate DATETIME DEFAULT GETDATE() ); -- 插入数据 INSERT INTO Studentsnew2 (StudentID, Name, Age, RegisterDate) VALUES (3, '王五', 21, '2023-10-02 10:30:00'), (4, '赵六', 19, '2023-10-03 14:15:00'), (5, '陈七', 23, DEFAULT); -- 使用默认值填充 RegisterDate -- 查询表 select * from Studentsnew2
二、表及数据恢复
1.停止对数据库增删改动作;设置为单用户模式
USE master; GO -- 设置数据库为单用户模式(强制断开现有连接) ALTER DATABASE [db_test] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; GO
2.对数据库做事务备份(15/58)
通过t-sql命令备份
要求:必须将数据库设置为 完整恢复模式 或 大容量日志恢复模式 才能备份事务日志
-- 检查恢复模式
SELECT name, recovery_model_desc FROM sys.databases where name='db_test';
-- 修改为完整恢复模式
ALTER DATABASE [db_test] SET RECOVERY FULL;
-- 事务日志备份
BACKUP LOG [db_test] TO DISK = 'C:\bak\dbtest1558.trn' WITH COMPRESSION, CHECKSUM;
可以通过SSMS备份
3.对数据库做完备
同上
4.通过删表前最近一次备份还原
--还原 RESTORE DATABASE [db_test] FROM DISK = 'C:\bak\dbtest1545.bak'WITH REPLACE;
5.确认表
说明:发现Students表恢复了,Studentsnew表不在,符合预期

-- 查询所有用户表(排除系统表) SELECT name AS TableName FROM sys.tables WHERE is_ms_shipped = 0
5.通过审计日志还原
说明: 需要知道删表时间
A.恢复到时间15/50,预期看到Studentsnew,Students
B.恢复到时间15/52 ,预期看不到Studentsnew,Students
C.恢复到时间15/54,预期看到Studentsnew2
补充:
1.可以直接用SSMS自带备份恢复操作
2.可以使用第三方工具ApexSQLLOG(经过实战尝试过, 目前最新支持到数据库2019)
3.演示完整命令

SELECT request_session_id FROM sys.dm_tran_locks WHERE resource_database_id = DB_ID('db_test'); kill 56 SELECT database_name, backup_start_date, backup_finish_date, physical_device_name FROM msdb.dbo.backupset AS bs INNER JOIN msdb.dbo.backupmediafamily AS bmf ON bs.media_set_id = bmf.media_set_id ORDER BY backup_finish_date DESC; -- 创建表和插入数据 CREATE TABLE Students ( StudentID INT PRIMARY KEY, Name NVARCHAR(50) NOT NULL, Age INT CHECK (Age >= 0), RegisterDate DATETIME DEFAULT GETDATE() ); -- 插入数据 INSERT INTO Students (StudentID, Name, Age, RegisterDate) VALUES (3, '王五', 21, '2023-10-02 10:30:00'), (4, '赵六', 19, '2023-10-03 14:15:00'), (5, '陈七', 23, DEFAULT); -- 使用默认值填充 RegisterDate -- 查询表 select * from Students ; --完整备份 BACKUP DATABASE [db_test] TO DISK = 'C:\bak\dbtest1545.bak'; -- 建表插入数据 CREATE TABLE Studentsnew ( StudentID INT PRIMARY KEY, Name NVARCHAR(50) NOT NULL, Age INT CHECK (Age >= 0), RegisterDate DATETIME DEFAULT GETDATE() ); -- 插入数据 INSERT INTO Studentsnew (StudentID, Name, Age, RegisterDate) VALUES (3, '王五', 21, '2023-10-02 10:30:00'), (4, '赵六', 19, '2023-10-03 14:15:00'), (5, '陈七', 23, DEFAULT); -- 使用默认值填充 RegisterDate -- 查询表 select * from Studentsnew -- drop table Studentsnew; drop table Students; -- 建表插入数据 CREATE TABLE Studentsnew2 ( StudentID INT PRIMARY KEY, Name NVARCHAR(50) NOT NULL, Age INT CHECK (Age >= 0), RegisterDate DATETIME DEFAULT GETDATE() ); -- 插入数据 INSERT INTO Studentsnew2 (StudentID, Name, Age, RegisterDate) VALUES (3, '王五', 21, '2023-10-02 10:30:00'), (4, '赵六', 19, '2023-10-03 14:15:00'), (5, '陈七', 23, DEFAULT); -- 使用默认值填充 RegisterDate -- 查询表 select * from Studentsnew2 USE master; GO -- 设置数据库为单用户模式(强制断开现有连接) ALTER DATABASE [db_test] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; GO -- 检查恢复模式 SELECT name, recovery_model_desc FROM sys.databases where name='db_test'; -- 修改为完整恢复模式 ALTER DATABASE [db_test] SET RECOVERY FULL; -- 事务日志备份 BACKUP LOG [db_test] TO DISK = 'C:\bak\dbtest1558.trn' WITH COMPRESSION, CHECKSUM; --WITH NORECOVERY -- 查询所有用户表(排除系统表) USE db_test SELECT name AS TableName FROM sys.tables WHERE is_ms_shipped = 0; select * from Students; --还原 USE master RESTORE DATABASE [db_test] FROM DISK = 'C:\bak\dbtest1545.bak' WITH REPLACE, NORECOVERY; RESTORE LOG [db_test] FROM DISK = 'C:\bak\dbtest1558.trn' WITH RECOVERY, STOPAT = '2025-03-06 15:54:00'; -- 指定恢复时间点 -- 查询所有用户表(排除系统表) USE db_test SELECT name AS TableName FROM sys.tables WHERE is_ms_shipped = 0; select * from Students; -- 恢复为多用户模式 USE master ALTER DATABASE [db_test] SET MULTI_USER; GO
4.备份还原不是同位置同名数据库

---在还原数据库前,需要知道备份文件中记录的逻辑文件名(可能与物理文件名不同): RESTORE FILELISTONLY FROM DISK ='C:\medPro_jufeng_prod_backup_2025_03_26_233001_1959260\medPro_jufeng_prod_backup_2025_03_26_233001_1959260.bak' --- 使用 WITH MOVE 重定向文件路径 RESTORE DATABASE medpro_jufeng0327 FROM DISK = 'C:\medPro_jufeng_prod_backup_2025_03_26_233001_1959260\medPro_jufeng_prod_backup_2025_03_26_233001_1959260.bak' WITH MOVE 'medPro_jufeng_test2' TO 'C:\Program Files\Microsoft SQL Server\MSSQL16.MSSQLSERVER\MSSQL\DATA\medpro_jufeng0327.mdf', MOVE 'medPro_jufeng_test2_log' TO 'C:\Program Files\Microsoft SQL Server\MSSQL16.MSSQLSERVER\MSSQL\DATA\medpro_jufeng0327_log.ldf', REPLACE; -- 如果存在同名数据库,使用 REPLACE 覆盖 --确认还原结果 USE master; SELECT name, state_desc FROM sys.databases WHERE name = 'medpro_jufeng0327';