SQL Server 2019入门学习教程,从入门到精通,SQL Server 2019 数据库的备份与恢复 — 语法知识点及使用方法详解(19)

SQL Server 2019 数据库的备份与恢复 --- 语法知识点及使用方法详解


一、备份与恢复介绍

数据库备份是防止数据丢失、应对灾难、满足合规审计的核心手段。SQL Server 提供多种备份类型和恢复模式,支持灵活的恢复策略。

📌 核心目标

  • 备份:创建数据库在特定时间点的副本。
  • 恢复:将数据库还原到某个备份时间点或指定时间点。

二、备份类型

备份类型 说明 适用场景
完整备份(Full Backup) 备份整个数据库(数据 + 日志) 基础备份,所有恢复的基础
差异备份(Differential Backup) 备份自上次完整备份以来更改的数据 减少备份大小和时间,需依赖完整备份
事务日志备份(Transaction Log Backup) 备份自上次日志备份以来的事务日志 支持时间点恢复,需完整或差异备份配合
文件/文件组备份(File/Filegroup Backup) 备份特定文件或文件组 大型数据库,部分文件损坏时快速恢复

⚠️ 注意

  • 差异备份基于最近一次完整备份,与中间差异备份无关。
  • 事务日志备份需在完整恢复模式大容量日志恢复模式下进行。
  • 文件备份适用于简单恢复模式以外的场景。

三、恢复模式

恢复模式决定事务日志管理方式,影响备份和恢复能力。

恢复模式 说明 备份支持 恢复能力
简单恢复模式(SIMPLE) 自动截断日志,不支持日志备份 完整、差异、文件备份 仅能恢复到完整或差异备份点
完整恢复模式(FULL) 保留所有日志,支持日志备份 完整、差异、日志、文件备份 支持时间点恢复
大容量日志恢复模式(BULK_LOGGED) 最小化大容量操作日志记录 完整、差异、日志、文件备份 支持时间点恢复(大容量操作期间除外)

📌 选择建议

  • 开发/测试环境 → 简单模式。
  • 生产OLTP系统 → 完整模式。
  • 数据仓库/ETL期间 → 临时切换为大容量日志模式。

3.1 配置恢复模式

语法:
sql 复制代码
ALTER DATABASE database_name 
SET RECOVERY { FULL | BULK_LOGGED | SIMPLE }
案例1:查看和设置恢复模式
sql 复制代码
-- 查看当前数据库恢复模式
SELECT name, recovery_model_desc 
FROM sys.databases 
WHERE name = 'CompanyDB';

-- 设置为完整恢复模式(生产推荐)
ALTER DATABASE CompanyDB SET RECOVERY FULL;

-- 设置为简单恢复模式(开发环境)
ALTER DATABASE CompanyDB SET RECOVERY SIMPLE;

-- 设置为大容量日志模式(执行大容量导入前)
ALTER DATABASE CompanyDB SET RECOVERY BULK_LOGGED;
GO

注释

  • 修改恢复模式后,建议立即进行一次完整备份。
  • 从简单模式切换到完整模式后,第一个事务日志备份会失败,需先做完整备份。

四、备份设备

备份设备是 SQL Server 存储备份的逻辑容器,可映射到磁盘文件或磁带设备。

4.1 备份设备类型

  • 磁盘设备.bak 文件(最常用)。
  • 磁带设备:物理磁带(企业级备份)。
  • Azure Blob 存储:云备份(SQL Server 2012 SP1+)。

📌 推荐使用磁盘文件,路径需确保 SQL Server 服务账户有读写权限。


4.2 创建备份设备

语法:
sql 复制代码
-- 创建永久备份设备(逻辑名映射到物理路径)
EXEC sp_addumpdevice 
    @devtype = 'disk' | 'tape', 
    @logicalname = 'logical_device_name', 
    @physicalname = 'physical_path';

-- 创建临时备份设备(直接在 BACKUP 语句中指定路径)
案例2:创建永久备份设备
sql 复制代码
-- 创建磁盘备份设备(逻辑名:CompanyDB_Full_Bak)
EXEC sp_addumpdevice 
    @devtype = 'disk', 
    @logicalname = 'CompanyDB_Full_Bak', 
    @physicalname = 'D:\SQLBackups\CompanyDB_Full.bak';

-- 创建日志备份设备
EXEC sp_addumpdevice 
    @devtype = 'disk', 
    @logicalname = 'CompanyDB_Log_Bak', 
    @physicalname = 'D:\SQLBackups\CompanyDB_Log.trn'; -- .trn 通常用于日志备份

-- 验证设备创建
SELECT * FROM sys.backup_devices;
GO

注释

  • sp_addumpdevice 创建的是永久逻辑设备,可重复使用。
  • 物理路径需确保 SQL Server 服务账户(如 NT Service\MSSQLSERVER)有写入权限。
  • 逻辑设备名是数据库引擎内部名称,与物理文件名无关。

4.3 查看备份设备

语法:
sql 复制代码
-- 查看所有备份设备
SELECT * FROM sys.backup_devices;

-- 使用系统存储过程
EXEC sp_helpdevice; -- 显示所有设备(包括数据设备)
案例3:查看备份设备信息
sql 复制代码
-- 查询备份设备
SELECT 
    name AS LogicalDeviceName,
    physical_name AS PhysicalPath,
    type_desc AS DeviceType
FROM sys.backup_devices;

-- 查看设备使用情况(需结合备份历史)
SELECT 
    bs.database_name,
    bs.backup_start_date,
    bs.backup_finish_date,
    bmf.physical_device_name,
    bs.type AS BackupType -- D=完整, I=差异, L=日志
FROM msdb.dbo.backupset bs
JOIN msdb.dbo.backupmediafamily bmf ON bs.media_set_id = bmf.media_set_id
WHERE bs.database_name = 'CompanyDB'
ORDER BY bs.backup_start_date DESC;
GO

注释

  • msdb 数据库存储备份历史记录。
  • backupset.type:D=完整,I=差异,L=日志。

4.4 删除备份设备

语法:
sql 复制代码
EXEC sp_dropdevice @logicalname = 'logical_device_name' [, @delfile = 'delfile'];
案例4:删除备份设备
sql 复制代码
-- 删除逻辑设备(不删除物理文件)
EXEC sp_dropdevice @logicalname = 'CompanyDB_Full_Bak';

-- 删除逻辑设备并删除物理文件(谨慎使用!)
EXEC sp_dropdevice @logicalname = 'CompanyDB_Log_Bak', @delfile = 'delfile';

-- 验证删除
SELECT * FROM sys.backup_devices WHERE name LIKE 'CompanyDB%';
GO

⚠️ 警告

  • @delfile = 'delfile'物理删除文件,不可恢复!
  • 生产环境建议先手动备份文件,再删除逻辑设备。

五、使用 Transact-SQL 语句备份数据库

5.1 完整备份与差异备份

语法:
sql 复制代码
-- 完整备份
BACKUP DATABASE database_name 
TO DISK = 'path' | TAPE = 'path' | <backup_device> 
[ WITH { FORMAT | INIT | SKIP | ... } ]

-- 差异备份
BACKUP DATABASE database_name 
TO DISK = 'path' 
WITH DIFFERENTIAL;
案例5:完整备份与差异备份
sql 复制代码
USE master;
GO

-- 1. 完整备份(基础备份)
BACKUP DATABASE CompanyDB 
TO DISK = 'D:\SQLBackups\CompanyDB_Full_20250914.bak'
WITH 
    FORMAT,          -- 初始化媒体集(覆盖现有备份)
    INIT,            -- 覆盖现有备份集(默认)
    NAME = 'Full Backup of CompanyDB', 
    DESCRIPTION = 'Full backup before major update',
    STATS = 10;      -- 每完成10%显示进度

-- 2. 执行一些数据修改(模拟业务操作)
USE CompanyDB;
GO
INSERT INTO dbo.Orders (CustomerID, OrderDate) VALUES (1, GETDATE());
GO

-- 3. 差异备份(仅备份更改部分)
BACKUP DATABASE CompanyDB 
TO DISK = 'D:\SQLBackups\CompanyDB_Diff_20250914_1.bak'
WITH 
    DIFFERENTIAL,    -- 关键字:差异备份
    NAME = 'Differential Backup 1',
    DESCRIPTION = 'After inserting test orders',
    STATS = 10;

-- 4. 再次修改数据
INSERT INTO dbo.Orders (CustomerID, OrderDate) VALUES (2, GETDATE());
GO

-- 5. 第二次差异备份(仍基于第一次完整备份)
BACKUP DATABASE CompanyDB 
TO DISK = 'D:\SQLBackups\CompanyDB_Diff_20250914_2.bak'
WITH DIFFERENTIAL, NAME = 'Differential Backup 2', STATS = 10;

-- 查看备份集信息
RESTORE HEADERONLY FROM DISK = 'D:\SQLBackups\CompanyDB_Full_20250914.bak';
RESTORE HEADERONLY FROM DISK = 'D:\SQLBackups\CompanyDB_Diff_20250914_2.bak';
GO

注释

  • FORMAT:初始化备份媒体,删除所有备份集。
  • INIT:追加到媒体,但覆盖同名备份集(默认行为)。
  • DIFFERENTIAL:指定差异备份。
  • STATS = 10:显示备份进度(每10%)。
  • RESTORE HEADERONLY:查看备份文件头信息(包含备份类型、LSN等)。

5.2 文件和文件组备份

适用于大型数据库,可单独备份/恢复特定文件组。

语法:
sql 复制代码
-- 文件备份
BACKUP DATABASE database_name 
FILE = 'logical_file_name' 
TO DISK = 'path'

-- 文件组备份
BACKUP DATABASE database_name 
FILEGROUP = 'filegroup_name' 
TO DISK = 'path'
案例6:文件组备份
sql 复制代码
-- 假设 CompanyDB 有文件组 'PRIMARY' 和 'FG_Sales'
-- 查看文件组
SELECT 
    name AS FileGroupName,
    type_desc 
FROM sys.filegroups;

-- 查看文件
SELECT 
    name AS LogicalFileName,
    physical_name AS PhysicalPath,
    type_desc,
    state_desc,
    filegroup_name = FILEGROUP_NAME(data_space_id)
FROM sys.database_files;

-- 备份 PRIMARY 文件组
BACKUP DATABASE CompanyDB 
FILEGROUP = 'PRIMARY' 
TO DISK = 'D:\SQLBackups\CompanyDB_PRIMARY_FG.bak'
WITH NAME = 'Primary Filegroup Backup', STATS = 10;

-- 备份特定文件(如主数据文件)
BACKUP DATABASE CompanyDB 
FILE = 'CompanyDB_Data' -- 逻辑文件名
TO DISK = 'D:\SQLBackups\CompanyDB_DataFile.bak'
WITH NAME = 'Data File Backup', STATS = 10;
GO

注释

  • 文件组备份需在完整大容量日志恢复模式下。
  • 恢复时需先还原完整数据库或文件组,再应用日志。

5.3 事务日志备份

语法:
sql 复制代码
BACKUP LOG database_name 
TO DISK = 'path' 
[ WITH { FORMAT | INIT | ... } ]
案例7:事务日志备份
sql 复制代码
-- 确保数据库在完整恢复模式
ALTER DATABASE CompanyDB SET RECOVERY FULL;
GO

-- 如果是首次日志备份,需先做完整备份
BACKUP DATABASE CompanyDB TO DISK = 'D:\SQLBackups\CompanyDB_Full_Init.bak' WITH INIT;
GO

-- 执行业务操作
USE CompanyDB;
INSERT INTO dbo.Orders (CustomerID, OrderDate) VALUES (3, GETDATE());
GO

-- 备份事务日志
BACKUP LOG CompanyDB 
TO DISK = 'D:\SQLBackups\CompanyDB_Log_20250914_1.trn'
WITH 
    NAME = 'Transaction Log Backup 1',
    STATS = 10;

-- 再次操作并备份日志
INSERT INTO dbo.Orders (CustomerID, OrderDate) VALUES (4, GETDATE());
GO
BACKUP LOG CompanyDB 
TO DISK = 'D:\SQLBackups\CompanyDB_Log_20250914_2.trn'
WITH NAME = 'Transaction Log Backup 2', STATS = 10;

-- 查看日志链
SELECT 
    database_name,
    backup_start_date,
    first_lsn,  -- 日志序列号起始
    last_lsn,   -- 日志序列号结束
    checkpoint_lsn,
    database_backup_lsn -- 关联的完整备份LSN
FROM msdb.dbo.backupset 
WHERE database_name = 'CompanyDB' AND type = 'L' -- L=Log
ORDER BY backup_start_date;
GO

注释

  • 事务日志备份必须在完整或大容量日志恢复模式下。
  • 日志备份会截断日志(释放空间),但不收缩文件。
  • first_lsnlast_lsn 用于确定日志备份的顺序和连续性。
  • 日志链断裂会导致无法恢复到最新状态!

六、在 SQL Server Management Studio (SSMS) 中还原数据库

⚠️ 还原前注意事项

  1. 备份当前状态:还原前备份尾日志(如果可能)。
  2. 独占访问:还原时数据库需处于单用户模式或无连接。
  3. 空间检查:确保目标磁盘有足够空间。
  4. 权限 :执行还原的账户需有 sysadmindbcreator 权限。
  5. 还原顺序:完整 → 差异 → 日志(按时间顺序)。

6.1 还原数据库的方式

  • 完整还原:从完整备份恢复整个数据库。
  • 差异还原:先还原完整备份,再还原差异备份。
  • 日志还原:还原完整/差异后,依次还原日志备份。
  • 时间点还原:还原到指定日期和时间。
  • 文件/文件组还原:还原特定文件或文件组。

6.2 还原数据库备份(SSMS 操作简述)

  1. 右键数据库 → 任务 → 还原 → 数据库。
  2. 选择源设备(备份文件)。
  3. 选择备份集(完整、差异、日志)。
  4. 选择"覆盖现有数据库"。
  5. 在"选项"页勾选"RESTRICTED_USER"或"单用户模式"。
  6. 点击"确定"执行还原。

📌 关键选项

  • RESTORE WITH REPLACE:强制覆盖(危险!)。
  • RESTORE WITH NORECOVERY:还原后保持"正在还原"状态(用于后续日志还原)。
  • RESTORE WITH RECOVERY:还原后使数据库可用(默认)。

七、使用 Transact-SQL 语句还原数据库

7.1 完整备份还原

语法:
sql 复制代码
RESTORE DATABASE database_name 
FROM DISK = 'path' 
[ WITH { REPLACE | NORECOVERY | RECOVERY | ... } ]
案例8:还原完整备份
sql 复制代码
-- 1. 将数据库设置为单用户模式(强制断开连接)
ALTER DATABASE CompanyDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO

-- 2. 还原完整备份(覆盖现有数据库)
RESTORE DATABASE CompanyDB 
FROM DISK = 'D:\SQLBackups\CompanyDB_Full_20250914.bak'
WITH 
    REPLACE,         -- 强制覆盖现有数据库
    RECOVERY,        -- 还原后使数据库可用
    STATS = 10;

-- 3. 恢复为多用户模式
ALTER DATABASE CompanyDB SET MULTI_USER;
GO

-- 验证数据
USE CompanyDB;
SELECT COUNT(*) FROM dbo.Orders; -- 应包含备份时的数据
GO

注释

  • SINGLE_USER WITH ROLLBACK IMMEDIATE:强制断开所有连接。
  • REPLACE:忽略数据库名称匹配和日志链检查(谨慎使用)。
  • RECOVERY:最后一步,使数据库在线。

7.2 差异备份还原

语法:
sql 复制代码
-- 先还原完整备份(NORECOVERY)
RESTORE DATABASE database_name FROM DISK = 'full_path' WITH NORECOVERY;

-- 再还原差异备份(RECOVERY 或 NORECOVERY)
RESTORE DATABASE database_name FROM DISK = 'diff_path' WITH RECOVERY;
案例9:还原完整 + 差异备份
sql 复制代码
-- 1. 设置单用户模式
ALTER DATABASE CompanyDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO

-- 2. 还原完整备份(保持NORECOVERY状态)
RESTORE DATABASE CompanyDB 
FROM DISK = 'D:\SQLBackups\CompanyDB_Full_20250914.bak'
WITH 
    REPLACE, 
    NORECOVERY, -- 关键:保持"正在还原"状态
    STATS = 10;

-- 3. 还原差异备份(应用更改)
RESTORE DATABASE CompanyDB 
FROM DISK = 'D:\SQLBackups\CompanyDB_Diff_20250914_2.bak'
WITH 
    RECOVERY,   -- 关键:完成还原,数据库可用
    STATS = 10;

-- 4. 恢复多用户模式
ALTER DATABASE CompanyDB SET MULTI_USER;
GO

-- 验证:应包含差异备份时的数据
USE CompanyDB;
SELECT COUNT(*) FROM dbo.Orders; -- 应比完整备份时多2条记录(案例5)
GO

注释

  • NORECOVERY 用于中间步骤,允许后续还原。
  • RECOVERY 用于最后一步,使数据库在线。

7.3 事务日志备份还原

语法:
sql 复制代码
-- 还原日志备份(通常在完整/差异后)
RESTORE LOG database_name 
FROM DISK = 'log_path' 
WITH NORECOVERY | RECOVERY;
案例10:完整 + 差异 + 日志还原(时间点恢复基础)
sql 复制代码
-- 目标:还原到第二个日志备份之后的状态

-- 1. 设置单用户模式
ALTER DATABASE CompanyDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO

-- 2. 还原完整备份(NORECOVERY)
RESTORE DATABASE CompanyDB 
FROM DISK = 'D:\SQLBackups\CompanyDB_Full_Init.bak' -- 案例7的完整备份
WITH 
    REPLACE, 
    NORECOVERY, 
    STATS = 10;

-- 3. 还原第一个日志备份(NORECOVERY)
RESTORE LOG CompanyDB 
FROM DISK = 'D:\SQLBackups\CompanyDB_Log_20250914_1.trn'
WITH NORECOVERY, STATS = 10;

-- 4. 还原第二个日志备份(RECOVERY)
RESTORE LOG CompanyDB 
FROM DISK = 'D:\SQLBackups\CompanyDB_Log_20250914_2.trn'
WITH RECOVERY, STATS = 10; -- 最后一步,数据库可用

-- 5. 恢复多用户模式
ALTER DATABASE CompanyDB SET MULTI_USER;
GO

-- 验证:应包含日志备份时插入的记录(CustomerID=3,4)
USE CompanyDB;
SELECT CustomerID, OrderDate FROM dbo.Orders WHERE CustomerID IN (3,4);
GO

注释

  • 日志备份必须按顺序还原(按 LSN 或时间)。
  • 最后一个日志备份用 RECOVERY
  • 中间日志备份用 NORECOVERY

7.4 文件和文件组备份还原

语法:
sql 复制代码
-- 还原文件组
RESTORE DATABASE database_name 
FILEGROUP = 'filegroup_name' 
FROM DISK = 'path' 
WITH NORECOVERY;

-- 还原后需应用日志
RESTORE LOG ... WITH RECOVERY;
案例11:还原文件组
sql 复制代码
-- 假设 FG_Sales 文件组损坏,需还原

-- 1. 设置单用户模式
ALTER DATABASE CompanyDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO

-- 2. 还原 FG_Sales 文件组(NORECOVERY)
RESTORE DATABASE CompanyDB 
FILEGROUP = 'FG_Sales' 
FROM DISK = 'D:\SQLBackups\CompanyDB_FG_Sales.bak'
WITH 
    REPLACE, 
    NORECOVERY, 
    STATS = 10;

-- 3. 还原必要的日志备份(使文件组数据一致)
RESTORE LOG CompanyDB 
FROM DISK = 'D:\SQLBackups\CompanyDB_Log_20250914_2.trn'
WITH RECOVERY, STATS = 10;

-- 4. 恢复多用户模式
ALTER DATABASE CompanyDB SET MULTI_USER;
GO

-- 验证文件组状态
SELECT 
    name AS FileGroupName,
    is_read_only,
    state_desc
FROM sys.filegroups 
WHERE name = 'FG_Sales';
GO

注释

  • 文件组还原后,数据库可能处于"部分还原"状态。
  • 必须应用足够的日志备份使文件组与数据库其他部分同步。
  • 未还原的文件组可能处于"离线"状态。

7.5 将数据库还原到某个时间点

语法:
sql 复制代码
-- 在日志还原时指定时间点
RESTORE LOG database_name 
FROM DISK = 'log_path' 
WITH 
    RECOVERY, 
    STOPAT = 'YYYY-MM-DD HH:MI:SS';
案例12:时间点还原(PITR - Point In Time Recovery)
sql 复制代码
-- 目标:还原到 2025-09-14 14:30:00 的状态

-- 1. 设置单用户模式
ALTER DATABASE CompanyDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO

-- 2. 还原完整备份(NORECOVERY)
RESTORE DATABASE CompanyDB 
FROM DISK = 'D:\SQLBackups\CompanyDB_Full_Init.bak'
WITH REPLACE, NORECOVERY, STATS = 10;

-- 3. 还原第一个日志备份(NORECOVERY)
RESTORE LOG CompanyDB 
FROM DISK = 'D:\SQLBackups\CompanyDB_Log_20250914_1.trn'
WITH NORECOVERY, STATS = 10;

-- 4. 还原第二个日志备份,但停止在指定时间点(RECOVERY)
RESTORE LOG CompanyDB 
FROM DISK = 'D:\SQLBackups\CompanyDB_Log_20250914_2.trn'
WITH 
    RECOVERY,
    STOPAT = '2025-09-14 14:30:00', -- 关键:指定时间点
    STATS = 10;

-- 5. 恢复多用户模式
ALTER DATABASE CompanyDB SET MULTI_USER;
GO

-- 验证:数据应包含到 14:30:00 为止的事务
USE CompanyDB;
SELECT GETDATE() AS CurrentTime; -- 注意:数据库时间未改变,数据状态改变
GO

注释

  • STOPAT 可精确到秒。
  • 时间点必须在日志备份的时间范围内。
  • 如果指定时间点在日志备份中间,SQL Server 会应用日志直到该时间点。
  • 适用于误删除、误更新后的精确恢复。

八、建立自动备份的维护计划

使用 SQL Server Agent 创建自动备份任务。

⚠️ 前提:SQL Server Agent 服务必须启动。

案例13:创建自动完整备份维护计划(T-SQL 脚本)

sql 复制代码
USE msdb;
GO

-- 1. 创建备份目录(确保路径存在且SQL服务账户有权限)
-- EXEC xp_create_subdir 'D:\AutoBackups\'; -- 取消注释以创建目录

-- 2. 创建作业(Job)
EXEC dbo.sp_add_job
    @job_name = N'Daily Full Backup - CompanyDB',
    @description = N'Automated daily full backup of CompanyDB',
    @enabled = 1; -- 启用作业

-- 3. 添加作业步骤
DECLARE @job_id UNIQUEIDENTIFIER;
SELECT @job_id = job_id FROM dbo.sysjobs WHERE name = N'Daily Full Backup - CompanyDB';

EXEC sp_add_jobstep
    @job_id = @job_id,
    @step_name = N'Backup CompanyDB',
    @subsystem = N'TSQL',
    @command = N'
        BACKUP DATABASE [CompanyDB] 
        TO DISK = N''D:\AutoBackups\CompanyDB_Full_'' + 
            REPLACE(CONVERT(VARCHAR, GETDATE(), 112), ''/'', '''') + ''.bak''
        WITH 
            INIT, 
            COMPRESSION, -- 启用压缩(SQL Server 2008+)
            NAME = N''Automated Full Backup'',
            STATS = 10;
    ',
    @on_success_action = 1, -- 成功后退出
    @on_fail_action = 2;    -- 失败后退出

-- 4. 创建作业调度(每天凌晨2点)
EXEC dbo.sp_add_schedule
    @schedule_name = N'Daily 2AM',
    @freq_type = 4,      -- 每天
    @freq_interval = 1,  -- 每1天
    @active_start_time = 020000; -- 02:00:00

-- 5. 将调度附加到作业
DECLARE @schedule_id INT;
SELECT @schedule_id = schedule_id FROM dbo.sysschedules WHERE name = N'Daily 2AM';

EXEC sp_attach_schedule
    @job_id = @job_id,
    @schedule_id = @schedule_id;

-- 6. 将作业添加到本地服务器
EXEC dbo.sp_add_jobserver
    @job_id = @job_id,
    @server_name = N'(local)';

-- 7. 启动作业(可选,测试用)
-- EXEC dbo.sp_start_job @job_name = N'Daily Full Backup - CompanyDB';

-- 8. 查看作业
SELECT name, enabled FROM dbo.sysjobs WHERE name LIKE '%CompanyDB%';
GO

注释

  • COMPRESSION:启用备份压缩,减少磁盘空间和I/O(企业版/标准版支持)。
  • REPLACE(CONVERT(VARCHAR, GETDATE(), 112), '/', ''):生成 YYYYMMDD 格式日期。
  • 作业历史记录存储在 msdb 数据库中。
  • 可通过 SSMS → SQL Server Agent → 作业 查看和管理。

九、通过 Always Encrypted 安全功能为数据加密

Always Encrypted 是客户端加密技术,确保数据在传输和存储时始终加密,SQL Server 无法访问明文密钥。

📌 核心组件

  • 列主密钥(CMK):存储在客户端或密钥库(如Windows证书存储)。
  • 列加密密钥(CEK):由 CMK 加密,存储在数据库中。
  • 加密列:使用 CEK 加密的数据列。

案例14:配置 Always Encrypted

sql 复制代码
USE CompanyDB;
GO

-- 步骤1:创建列主密钥(CMK)
-- 注意:此操作通常在 SSMS 中通过向导完成(需配置密钥存储)
-- 以下为 T-SQL 示例(需启用 Always Encrypted 功能)

-- 创建列主密钥元数据(指向Windows证书存储)
CREATE COLUMN MASTER KEY CMK_Auto1
WITH (
    KEY_STORE_PROVIDER_NAME = N'MSSQL_CERTIFICATE_STORE',
    KEY_PATH = N'CurrentUser/My/CERTIFICATE_THUMBPRINT' -- 替换为实际证书指纹
);
GO

-- 步骤2:创建列加密密钥(CEK)
CREATE COLUMN ENCRYPTION KEY CEK_Auto1
WITH VALUES (
    COLUMN_MASTER_KEY = CMK_Auto1,
    ALGORITHM = 'RSA_OAEP',
    ENCRYPTED_VALUE = 0x... -- 实际值由向导生成
);
GO

-- 步骤3:创建加密表或修改现有表
-- 创建新表
CREATE TABLE dbo.EncryptedCustomers (
    CustomerID INT IDENTITY(1,1) PRIMARY KEY,
    FirstName NVARCHAR(50) COLLATE Latin1_General_BIN2 
        ENCRYPTED WITH (
            COLUMN_ENCRYPTION_KEY = CEK_Auto1,
            ENCRYPTION_TYPE = Deterministic, -- 支持等值查询
            ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'
        ),
    SSN CHAR(11) COLLATE Latin1_General_BIN2 
        ENCRYPTED WITH (
            COLUMN_ENCRYPTION_KEY = CEK_Auto1,
            ENCRYPTION_TYPE = Randomized, -- 更安全,不支持查询
            ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'
        )
);
GO

-- 步骤4:插入数据(需在支持 Always Encrypted 的客户端执行,如SSMS启用AE)
-- INSERT INTO dbo.EncryptedCustomers (FirstName, SSN) VALUES ('Alice', '123-45-6789');

-- 步骤5:查询数据(客户端自动解密)
-- SELECT * FROM dbo.EncryptedCustomers; -- 在支持AE的客户端显示明文

-- 查看加密列信息
SELECT 
    t.name AS TableName,
    c.name AS ColumnName,
    cek.name AS ColumnEncryptionKeyName,
    c.encryption_type_desc,
    c.encryption_algorithm_name
FROM sys.columns c
JOIN sys.column_encryption_keys cek ON c.column_encryption_key_id = cek.column_encryption_key_id
JOIN sys.tables t ON c.object_id = t.object_id
WHERE c.encryption_type IS NOT NULL;
GO

注释

  • Deterministic:相同明文产生相同密文,支持等值查询、分组、连接。
  • Randomized:相同明文产生不同密文,更安全,但不支持查询。
  • 客户端要求:应用程序或 SSMS 必须启用 Always Encrypted 并能访问 CMK。
  • SQL Server 永远无法看到明文数据!

十、动态数据屏蔽(Dynamic Data Masking)

动态数据屏蔽在查询结果中隐藏敏感数据,无需修改数据本身。

📌 适用场景:客服人员查看客户信息时隐藏部分手机号、邮箱等。

案例15:配置动态数据屏蔽

sql 复制代码
USE CompanyDB;
GO

-- 1. 创建测试表
CREATE TABLE dbo.MaskedCustomers (
    CustomerID INT IDENTITY(1,1) PRIMARY KEY,
    FirstName NVARCHAR(50),
    Email VARCHAR(100),
    PhoneNumber VARCHAR(15),
    CreditCard VARCHAR(19),
    Salary DECIMAL(10,2)
);
GO

-- 2. 插入测试数据
INSERT INTO dbo.MaskedCustomers (FirstName, Email, PhoneNumber, CreditCard, Salary)
VALUES 
    ('Alice', 'alice@example.com', '13800138000', '1234-5678-9012-3456', 85000.00),
    ('Bob', 'bob@test.org', '13900139000', '9876-5432-1098-7654', 92000.00);
GO

-- 3. 添加动态数据屏蔽规则
ALTER TABLE dbo.MaskedCustomers
ALTER COLUMN Email ADD MASKED WITH (FUNCTION = 'email()'); -- 邮箱格式屏蔽

ALTER TABLE dbo.MaskedCustomers
ALTER COLUMN PhoneNumber ADD MASKED WITH (FUNCTION = 'partial(3,"XXXXXXX",2)'); 
-- 保留前3后2,中间用X填充 → 138XXXXXXX00

ALTER TABLE dbo.MaskedCustomers
ALTER COLUMN CreditCard ADD MASKED WITH (FUNCTION = 'partial(0,"XXXX-XXXX-XXXX-",4)'); 
-- 显示后4位 → XXXX-XXXX-XXXX-3456

ALTER TABLE dbo.MaskedCustomers
ALTER COLUMN Salary ADD MASKED WITH (FUNCTION = 'default()'); -- 默认屏蔽(数字显示0)
GO

-- 4. 创建普通用户(无UNMASK权限)
CREATE USER masked_user WITHOUT LOGIN; -- 无登录用户用于测试
GRANT SELECT ON dbo.MaskedCustomers TO masked_user;
GO

-- 5. 以普通用户身份查询(数据被屏蔽)
EXECUTE AS USER = 'masked_user';
SELECT * FROM dbo.MaskedCustomers;
-- 结果示例:
-- Email: aXXX@XXXX.com
-- PhoneNumber: 138XXXXXXX00
-- CreditCard: XXXX-XXXX-XXXX-3456
-- Salary: 0.00
REVERT;
GO

-- 6. 创建特权用户(有UNMASK权限)
CREATE USER unmask_user WITHOUT LOGIN;
GRANT SELECT ON dbo.MaskedCustomers TO unmask_user;
GRANT UNMASK TO unmask_user; -- 关键:授予UNMASK权限
GO

-- 7. 以特权用户身份查询(显示明文)
EXECUTE AS USER = 'unmask_user';
SELECT * FROM dbo.MaskedCustomers;
-- 显示原始数据
REVERT;
GO

-- 8. 查看屏蔽规则
SELECT 
    t.name AS TableName,
    c.name AS ColumnName,
    mc.masking_function AS MaskingFunction
FROM sys.masked_columns mc
JOIN sys.tables t ON mc.object_id = t.object_id
JOIN sys.columns c ON mc.object_id = c.object_id AND mc.column_id = c.column_id
WHERE t.name = 'MaskedCustomers';
GO

-- 9. 删除屏蔽规则
ALTER TABLE dbo.MaskedCustomers ALTER COLUMN Email DROP MASKED;
-- 或删除整个表重建
GO

注释

  • email():自动屏蔽邮箱(保留首字母和域名)。
  • partial(prefix, padding, suffix):自定义屏蔽格式。
  • default():根据数据类型默认屏蔽(字符串→XXXX,数字→0,日期→1900-01-01)。
  • UNMASK 权限控制谁能看到明文。
  • 无性能开销:屏蔽在结果返回前应用。

十一、综合性案例

综合案例1:构建完整的备份恢复策略

sql 复制代码
-- 场景:为生产数据库 CompanyDB 设计完整备份策略(完整+差异+日志)

USE master;
GO

-- 步骤1:设置恢复模式为完整
ALTER DATABASE CompanyDB SET RECOVERY FULL;
GO

-- 步骤2:创建备份目录(确保路径存在)
-- EXEC xp_create_subdir 'D:\ProductionBackups\';

-- 步骤3:执行初始完整备份
BACKUP DATABASE CompanyDB 
TO DISK = 'D:\ProductionBackups\CompanyDB_Full_Initial.bak'
WITH 
    INIT, 
    COMPRESSION, 
    NAME = 'Initial Full Backup for Production',
    STATS = 10;
GO

-- 步骤4:创建自动备份作业(完整、差异、日志)

USE msdb;
GO

-- 4.1 每周日完整备份
EXEC sp_add_job @job_name = 'Weekly Full Backup - CompanyDB', @enabled = 1;
-- ... 添加步骤和调度(参考案例13,每周日执行)

-- 4.2 每天差异备份(除周日外)
EXEC sp_add_job @job_name = 'Daily Differential Backup - CompanyDB', @enabled = 1;
-- ... 添加步骤:BACKUP DATABASE ... WITH DIFFERENTIAL
-- ... 调度:每天,除周日

-- 4.3 每15分钟事务日志备份
EXEC sp_add_job @job_name = 'Every 15min Log Backup - CompanyDB', @enabled = 1;
-- ... 添加步骤:BACKUP LOG ...
-- ... 调度:每15分钟

-- 步骤5:模拟灾难恢复(还原到最新状态)
-- 假设数据库损坏,需还原

USE master;
GO

-- 5.1 尾日志备份(如果可能)
-- BACKUP LOG CompanyDB TO DISK = 'D:\ProductionBackups\tail.trn' WITH NORECOVERY;

-- 5.2 还原最新完整备份
ALTER DATABASE CompanyDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
RESTORE DATABASE CompanyDB 
FROM DISK = 'D:\ProductionBackups\CompanyDB_Full_Initial.bak'
WITH REPLACE, NORECOVERY, STATS = 10;

-- 5.3 还原最新差异备份
RESTORE DATABASE CompanyDB 
FROM DISK = 'D:\ProductionBackups\CompanyDB_Diff_Latest.bak'
WITH NORECOVERY, STATS = 10;

-- 5.4 按顺序还原所有日志备份(包括尾日志)
RESTORE LOG CompanyDB FROM DISK = 'D:\ProductionBackups\Log1.trn' WITH NORECOVERY;
RESTORE LOG CompanyDB FROM DISK = 'D:\ProductionBackups\Log2.trn' WITH NORECOVERY;
-- ... 继续还原所有日志
RESTORE LOG CompanyDB FROM DISK = 'D:\ProductionBackups\tail.trn' WITH RECOVERY;

-- 5.5 恢复多用户模式
ALTER DATABASE CompanyDB SET MULTI_USER;
GO

-- 步骤6:验证数据一致性
USE CompanyDB;
DBCC CHECKDB WITH NO_INFOMSGS;
GO

注释

  • 完整备份每周一次,减少I/O压力。
  • 差异备份每天一次,减少备份大小。
  • 日志备份每15分钟,确保最多丢失15分钟数据。
  • 尾日志备份在灾难前尽可能捕获最后事务。
  • DBCC CHECKDB 验证还原后数据库完整性。

综合案例2:安全备份与合规性加固

sql 复制代码
-- 场景:结合加密、屏蔽、审计的备份恢复方案

USE master;
GO

-- 1. 启用透明数据加密(TDE) - 数据库级加密(需企业版)
-- CREATE DATABASE ENCRYPTION KEY ... 
-- ALTER DATABASE ... SET ENCRYPTION ON;

-- 2. 对敏感列使用 Always Encrypted(如身份证号)
USE CompanyDB;
GO
-- ... 参考案例14配置AE

-- 3. 对非敏感但需保护的列使用动态数据屏蔽(如薪资)
-- ... 参考案例15配置DDM

-- 4. 创建审计跟踪备份操作
USE master;
GO
CREATE SERVER AUDIT BackupAudit
TO FILE (FILEPATH = 'D:\AuditLogs\', MAXSIZE = 100 MB)
WITH (QUEUE_DELAY = 1000, ON_FAILURE = CONTINUE);

CREATE SERVER AUDIT SPECIFICATION BackupAuditSpec
FOR SERVER AUDIT BackupAudit
ADD (BACKUP_RESTORE_GROUP); -- 审计所有备份还原操作

ALTER SERVER AUDIT BackupAudit WITH (STATE = ON);
ALTER SERVER AUDIT SPECIFICATION BackupAuditSpec WITH (STATE = ON);
GO

-- 5. 创建安全的备份作业(备份到加密卷或网络共享)
USE msdb;
GO
-- 创建作业,备份到安全位置(如 \\SecureServer\Backups\)
-- 确保网络共享权限严格控制

-- 6. 验证审计记录
SELECT 
    event_time,
    server_principal_name,
    database_name,
    statement
FROM sys.fn_get_audit_file('D:\AuditLogs\*.sqlaudit', DEFAULT, DEFAULT)
WHERE action_id IN ('BAC', 'REST'); -- BAC=Backup, REST=Restore
GO

-- 7. 清理(测试后)
-- ALTER SERVER AUDIT SPECIFICATION BackupAuditSpec WITH (STATE = OFF);
-- DROP SERVER AUDIT SPECIFICATION BackupAuditSpec;
-- ALTER SERVER AUDIT BackupAudit WITH (STATE = OFF);
-- DROP SERVER AUDIT BackupAudit;
GO

注释

  • TDE:加密整个数据库文件(静态加密)。
  • Always Encrypted:保护特定列,即使DBA也无法查看。
  • 动态数据屏蔽:控制应用层数据可见性。
  • 审计:跟踪谁在何时执行了备份/还原操作。
  • 备份文件应存储在访问受控的位置。

十二、最佳实践与注意事项

✅ 最佳实践:

  1. 3-2-1 备份规则

    • 至少 3 份数据副本。
    • 存储在 2 种不同介质。
    • 1 份异地存储(如云、磁带)。
  2. 定期测试恢复:备份无效,除非你测试过恢复!

  3. 监控备份作业:设置警报,确保备份成功。

  4. 压缩备份 :节省空间和网络带宽(WITH COMPRESSION)。

  5. 验证备份 :使用 RESTORE VERIFYONLY 验证备份完整性。

  6. 清理旧备份:使用维护计划或脚本删除过期备份。

  7. 文档化恢复步骤:确保团队知道如何执行灾难恢复。

  8. 结合多种技术:备份 + Always Encrypted + TDE + 审计。

⚠️ 注意事项:

  1. 日志链连续性:日志备份中断会导致无法恢复到最新状态。
  2. 空间管理:备份文件会占用大量空间,需定期清理。
  3. 权限最小化 :备份操作账户只需 db_backupoperator 角色。
  4. 网络备份风险:备份到网络路径需确保网络稳定和权限安全。
  5. Always Encrypted 限制:不支持所有数据类型和操作(如范围查询)。
  6. 动态数据屏蔽不是安全机制:只是隐藏显示,数据仍存储明文。
  7. 恢复模式选择:根据业务需求选择,避免在简单模式下需要日志恢复。

✅ 本章全面覆盖 SQL Server 2019 备份与恢复的核心技术,从基础备份类型、恢复模式到高级的 Always Encrypted 和动态数据屏蔽,并提供实战案例。建立完善的备份恢复策略是保障业务连续性的基石!

相关推荐
倔强的石头1061 小时前
一卡通核心交易平台的国产数据库实践解析:架构、迁移与高可用落地
数据库·架构·kingbase
GDAL2 小时前
SQLite 核心特性与应用实战教程:轻量却不简单的嵌入式数据库
数据库·sqlite
風清掦2 小时前
【江科大STM32学习笔记-06】TIM 定时器 - 6.2 定时器的输出比较功能
笔记·stm32·单片机·嵌入式硬件·学习
源码获取_wx:Fegn08952 小时前
计算机毕业设计|基于springboot + vue家政服务平台系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
空空潍2 小时前
Redis点评实战篇-关注推送
java·数据库·redis·缓存
babe小鑫2 小时前
大专数据可视化技术专业学习数据分析的价值
学习·信息可视化·数据分析
Non importa2 小时前
二分法:算法新手第三道坎
c语言·c++·笔记·qt·学习·算法·leetcode
+VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue社区智慧消防管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
山岚的运维笔记2 小时前
SQL Server笔记 -- 第74章:权限或许可 第75章:SQLCMD 第76章:资源调控器
数据库·笔记·sql·microsoft·oracle·sqlserver