SQL Server 管理系列(第五期):自动化运维——SQL Agent 作业与多服务器管理

0 阅读9分钟

SQL Server 管理系列(第五期):自动化运维——SQL Agent 作业与多服务器管理

上一期我们学习了高可用架构。这一期,我们进入 DBA 日常工作的核心——自动化运维。你是否遇到过:每天凌晨 3 点起床做数据库备份?服务器数量增长后,逐一登录执行维护任务?半夜收到磁盘空间告警,却只能手动清理?这一期,我们教你用 SQL Server Agent 把重复性工作交给机器,让 DBA 从“消防员”变成“架构师”。

一、SQL Server Agent 概述

1.1 Agent 的核心组件

┌─────────────────────────────────────────────────────────────┐
│                    SQL Server Agent                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │
│  │    作业      │  │   操作员     │  │    警报      │          │
│  │   Job       │  │  Operator   │  │   Alert     │          │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘          │
│         │                │                │                  │
│         └────────────────┼────────────────┘                  │
│                          ▼                                   │
│  ┌─────────────────────────────────────────────────────┐    │
│  │                    步骤 (Steps)                       │    │
│  │  T-SQL │ PowerShell │ CmdExec │ SSIS │ 复制  │ 分析服务  │    │
│  └─────────────────────────────────────────────────────┘    │
│  ┌─────────────────────────────────────────────────────┐    │
│  │                   调度 (Schedules)                    │    │
│  │  一次性 │ 重复执行 │ 按CPU空闲 │ 启动时                │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘

1.2 启用和配置 SQL Agent

-- 查看 Agent 状态
SELECT 
    name,
    is_enabled,
    CASE status 
        WHEN 1 THEN 'Running'
        WHEN 2 THEN 'Paused'
        WHEN 3 THEN 'Stopped'
        WHEN 4 THEN 'Starting'
    END AS AgentStatus
FROM msdb.dbo.sysjobscheduler

-- 启动 SQL Agent(使用 SQL Server 配置管理器或 PowerShell)
Start-Service SQLSERVERAGENT  -- 默认实例
Start-Service SQLAgent$InstanceName  -- 命名实例

-- 查看 Agent 错误日志
EXEC xp_readerrorlog 0, 1, 'Agent', NULL, '2024-01-01', '2024-01-02', N'DESC'

二、作业(Job)深度配置

2.1 创建作业的标准模板

USE msdb;
GO

-- 1. 创建作业
EXEC dbo.sp_add_job
    @job_name = N'DBA_DailyMaintenance',
    @enabled = 1,
    @description = N'每日数据库维护:更新统计信息、检查一致性、清理历史',
    @owner_login_name = N'sa',
    @notify_level_eventlog = 2,  -- 失败时写入日志
    @notify_level_email = 2,     -- 失败时发送邮件
    @notify_level_netsend = 0,
    @notify_level_page = 0;

-- 2. 创建步骤1:更新统计信息
EXEC dbo.sp_add_jobstep
    @job_name = N'DBA_DailyMaintenance',
    @step_name = N'更新统计信息',
    @step_id = 1,
    @command = N'
        EXEC sp_updatestats;
        -- 或针对特定表
        UPDATE STATISTICS YourDB.dbo.Orders WITH FULLSCAN;
    ',
    @database_name = N'YourDB',
    @on_success_action = 3,  -- 成功则继续下一步
    @on_fail_action = 2;     -- 失败则终止

-- 3. 创建步骤2:检查数据库完整性
EXEC dbo.sp_add_jobstep
    @job_name = N'DBA_DailyMaintenance',
    @step_name = N'DBCC CHECKDB',
    @step_id = 2,
    @command = N'DBCC CHECKDB(YourDB) WITH NO_INFOMSGS, PHYSICAL_ONLY',
    @database_name = N'YourDB',
    @on_success_action = 3,
    @on_fail_action = 1;  -- 失败后报告成功(记录错误但不终止作业)

-- 4. 创建调度(每天凌晨2点)
EXEC dbo.sp_add_schedule
    @schedule_name = N'Daily_2AM',
    @freq_type = 4,          -- 每天
    @freq_interval = 1,      -- 每1天
    @active_start_time = 20000,  -- 02:00:00
    @active_end_time = 235959;

EXEC dbo.sp_attach_schedule
    @job_name = N'DBA_DailyMaintenance',
    @schedule_name = N'Daily_2AM';

-- 5. 添加目标服务器(多服务器管理)
EXEC dbo.sp_add_jobserver
    @job_name = N'DBA_DailyMaintenance',
    @server_name = N'(local)';

-- 6. 立即启动作业(测试)
EXEC dbo.sp_start_job @job_name = N'DBA_DailyMaintenance';

2.2 作业步骤类型详解

类型适用场景示例
T-SQL数据库操作、维护备份、统计信息、索引重建
CmdExec操作系统命令、PowerShell磁盘清理、文件复制
PowerShell复杂文件操作、云 APIAzure 备份、S3 上传
SSISETL 数据导入导出数据仓库加载
复制复制代理同步订阅
分析服务SSAS 处理多维数据集刷新
-- CmdExec 示例:清理旧备份文件
EXEC dbo.sp_add_jobstep
    @job_name = N'Backup_Cleanup',
    @step_name = N'删除7天前备份',
    @subsystem = N'CmdExec',
    @command = N'
        forfiles /p "G:\Backup" /s /m *.bak /d -7 /c "cmd /c del @file"
        forfiles /p "G:\Backup" /s /m *.trn /d -7 /c "cmd /c del @file"
    ';

-- PowerShell 示例:发送备份报告到 S3
EXEC dbo.sp_add_jobstep
    @job_name = N'Backup_To_Azure',
    @step_name = N'上传到Azure Blob',
    @subsystem = N'PowerShell',
    @command = N'
        $ctx = New-AzStorageContext -StorageAccountName "myaccount" -StorageAccountKey "key"
        $blob = Get-AzStorageBlob -Container "backups" -Context $ctx
        Set-AzStorageBlobContent -File "G:\Backup\YourDB.bak" -Container "backups" -Context $ctx
    ';

2.3 作业调度频率配置

-- 调度参数说明
-- freq_type: 1=一次, 4=每天, 8=每周, 16=每月, 32=每月相对, 64=启动时, 128=CPU空闲

-- 每周一到周五 09:00 执行
EXEC dbo.sp_add_schedule
    @schedule_name = N'Weekday_9AM',
    @freq_type = 8,           -- 每周
    @freq_interval = 62,      -- 周一至周五(2+4+8+16+32)
    @freq_recurrence_factor = 1,
    @active_start_time = 90000;  -- 09:00:00

-- 每月最后一天 23:00 执行
EXEC dbo.sp_add_schedule
    @schedule_name = N'LastDayOfMonth',
    @freq_type = 16,          -- 每月
    @freq_interval = 1,       -- 第1天(但配合 @freq_relative_interval)
    @freq_relative_interval = 10, -- 最后一周
    @freq_recurrence_factor = 1,
    @active_start_time = 230000;

-- 每15分钟执行(用于日志备份)
EXEC dbo.sp_add_schedule
    @schedule_name = N'Every_15Min',
    @freq_type = 4,           -- 每天
    @freq_interval = 1,
    @freq_subday_type = 4,    -- 分钟间隔
    @freq_subday_interval = 15,
    @active_start_time = 0;

三、操作员(Operator)与警报(Alert)

3.1 创建操作员

-- 创建邮件操作员
EXEC msdb.dbo.sp_add_operator
    @name = N'DBA_Team',
    @enabled = 1,
    @email_address = N'dba@company.com',
    @pager_email_address = N'dba-pager@company.com',  -- 紧急通知
    @weekday_pager_start_time = 80000,   -- 08:00-20:00
    @weekday_pager_end_time = 200000,
    @saturday_pager_start_time = 0,      -- 全天候
    @saturday_pager_end_time = 235959,
    @sunday_pager_start_time = 0,
    @sunday_pager_end_time = 235959,
    @netsend_address = N'DBA_Computer';

-- 创建多个操作员用于不同级别告警
EXEC sp_add_operator @name = N'Critical_Team', @email_address = N'critical@company.com';
EXEC sp_add_operator @name = N'Warning_Team', @email_address = N'warning@company.com';

3.2 配置数据库邮件

-- 1. 启用 Database Mail
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'Database Mail XPs', 1;
RECONFIGURE;

-- 2. 创建邮件配置文件
EXEC msdb.dbo.sysmail_add_profile_sp
    @profile_name = 'SQL_Alert_Profile',
    @description = 'SQL Server 告警邮件配置';

-- 3. 添加邮件账户
EXEC msdb.dbo.sysmail_add_account_sp
    @account_name = 'SQL_Alert_Account',
    @email_address = 'sqlalert@company.com',
    @display_name = 'SQL Server 告警',
    @mailserver_name = 'smtp.company.com',
    @port = 25;

-- 4. 关联账户到配置文件
EXEC msdb.dbo.sysmail_add_profileaccount_sp
    @profile_name = 'SQL_Alert_Profile',
    @account_name = 'SQL_Alert_Account',
    @sequence_number = 1;

-- 5. 设置默认配置文件
EXEC msdb.dbo.sysmail_configure_sp
    @parameter_name = 'DefaultProfile',
    @parameter_value = 'SQL_Alert_Profile';

-- 6. 配置 SQL Agent 使用该配置文件
EXEC msdb.dbo.sp_set_sqlagent_properties
    @databasemail_profile = 'SQL_Alert_Profile';

3.3 创建警报

-- 严重错误警报(错误级别 19-25)
EXEC msdb.dbo.sp_add_alert
    @name = N'严重数据库错误',
    @message_id = 0,
    @severity = 019,  -- 严重级别 19-25
    @enabled = 1,
    @delay_between_responses = 60,  -- 60秒内不重复告警
    @notification_message = N'检测到严重数据库错误,请立即处理!',
    @include_event_description_in = 1,
    @database_name = NULL,
    @event_description_keyword = NULL;

-- 特定错误号警报(如死锁 1205)
EXEC msdb.dbo.sp_add_alert
    @name = N'死锁检测',
    @message_id = 1205,
    @severity = 0,
    @enabled = 1,
    @delay_between_responses = 300,
    @notification_message = N'检测到死锁,请检查应用程序。';

-- 性能条件警报(磁盘空间不足)
EXEC msdb.dbo.sp_add_alert
    @name = N'磁盘空间不足',
    @performance_condition = N'LogicalDisk|% Free Space|C:|<|10',
    @category_name = N'Performance',
    @severity = 0,
    @enabled = 1;

-- 关联警报到操作员
EXEC msdb.dbo.sp_add_notification
    @alert_name = N'死锁检测',
    @operator_name = N'DBA_Team',
    @notification_method = 1;  -- 1=邮件, 2=寻呼, 4=网络发送, 7=全部

四、多服务器管理(MSX/TSX)

4.1 架构说明

┌─────────────────────────────────────────────────────────────┐
│                    主服务器 (MSX)                            │
│                  Master Server                               │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐                      │
│  │ 作业1    │  │ 作业2    │  │ 作业3    │                      │
│  │ 备份    │  │ 索引    │  │ 一致性  │                      │
│  └────┬────┘  └────┬────┘  └────┬────┘                      │
│       │            │            │                            │
│       └────────────┼────────────┘                            │
│                    ▼                                         │
│            ┌───────────────┐                                 │
│            │  分发作业      │                                 │
│            └───────┬───────┘                                 │
└────────────────────┼─────────────────────────────────────────┘
                     │
         ┌───────────┼───────────┬───────────────┐
         ▼           ▼           ▼               ▼
    ┌─────────┐ ┌─────────┐ ┌─────────┐    ┌─────────┐
    │ 目标1    │ │ 目标2    │ │ 目标3    │    │ 目标N    │
    │ TSX     │ │ TSX     │ │ TSX     │    │ TSX     │
    └─────────┘ └─────────┘ └─────────┘    └─────────┘

4.2 配置主服务器(MSX)

-- 1. 在目标服务器上登记到主服务器(在目标服务器执行)
EXEC msdb.dbo.sp_msx_enlist 
    @msx_server_name = N'CentralDBServer';

-- 2. 查看登记的服务器
EXEC msdb.dbo.sp_help_targetserver;

-- 3. 强制目标服务器刷新作业列表
EXEC msdb.dbo.sp_post_msx_operation 
    @operation = 'RE-ENLIST',
    @object_type = 'SERVER',
    @specific_target_server = N'TargetServer01';

-- 4. 从主服务器删除目标服务器
EXEC msdb.dbo.sp_msx_defect 
    @target_server = N'TargetServer01';

4.3 创建多服务器作业

-- 在主服务器上创建作业(会自动分发到所有目标服务器)
EXEC dbo.sp_add_job
    @job_name = N'MSX_DailyBackup',
    @enabled = 1,
    @description = N'所有服务器的每日备份',
    @owner_login_name = N'sa';

-- 添加步骤(在所有目标服务器上执行)
EXEC dbo.sp_add_jobstep
    @job_name = N'MSX_DailyBackup',
    @step_name = N'完整备份',
    @command = N'
        DECLARE @dbname sysname
        DECLARE cur CURSOR FOR 
            SELECT name FROM sys.databases 
            WHERE name NOT IN (''tempdb'') AND state = 0
        
        OPEN cur
        FETCH NEXT FROM cur INTO @dbname
        WHILE @@FETCH_STATUS = 0
        BEGIN
            BACKUP DATABASE @dbname 
            TO DISK = ''D:\Backup\'' + @dbname + ''_'' + CONVERT(VARCHAR, GETDATE(), 112) + ''.bak''
            WITH COMPRESSION
            FETCH NEXT FROM cur INTO @dbname
        END
        CLOSE cur
        DEALLOCATE cur
    ';

-- 调度(统一执行时间)
EXEC dbo.sp_add_schedule
    @schedule_name = N'Global_Midnight',
    @freq_type = 4,
    @freq_interval = 1,
    @active_start_time = 0;

EXEC dbo.sp_attach_schedule
    @job_name = N'MSX_DailyBackup',
    @schedule_name = N'Global_Midnight';

-- 分发到所有目标服务器
EXEC dbo.sp_add_jobserver
    @job_name = N'MSX_DailyBackup',
    @server_name = N'(ALL)';

-- 查看作业在各目标服务器的状态
SELECT 
    sj.name AS JobName,
    sjs.last_run_date,
    sjs.last_run_time,
    sjs.last_outcome_message,
    st.name AS TargetServer
FROM msdb.dbo.sysjobs sj
JOIN msdb.dbo.sysjobservers sjs ON sj.job_id = sjs.job_id
JOIN msdb.dbo.systargetservers st ON sjs.server_id = st.server_id
WHERE sj.name = 'MSX_DailyBackup';

五、运维自动化实战案例

5.1 磁盘空间监控与自动清理

-- 作业:每日检查磁盘空间,不足时自动清理

-- 步骤1:检查磁盘空间(T-SQL)
CREATE PROC dbo.CheckDiskSpace
AS
BEGIN
    CREATE TABLE #DiskSpace (Drive CHAR(1), FreeMB INT)
    INSERT INTO #DiskSpace
    EXEC xp_fixeddrives
    
    IF EXISTS (SELECT 1 FROM #DiskSpace WHERE FreeMB < 10240)  -- 小于10GB
        THROW 50001, '磁盘空间不足', 1
END

-- 步骤2:自动清理(CmdExec)
-- forfiles /p "D:\Backup" /s /m *.bak /d -3 /c "cmd /c del @file"

-- 步骤3:发送报告
EXEC msdb.dbo.sp_send_dbmail
    @profile_name = 'SQL_Alert_Profile',
    @recipients = 'dba@company.com',
    @subject = '磁盘空间报告',
    @body = '当前磁盘空间:...';

5.2 索引维护自动化

-- 智能索引维护:根据碎片率决定重组或重建
CREATE PROC dbo.IndexMaintenance
    @DBName NVARCHAR(128),
    @MinFragmentation INT = 5,
    @MaxFragmentation INT = 30
AS
BEGIN
    DECLARE @SQL NVARCHAR(MAX)
    DECLARE @TableName NVARCHAR(128)
    DECLARE @IndexName NVARCHAR(128)
    DECLARE @Fragmentation DECIMAL(5,2)
    
    DECLARE idx_cursor CURSOR FOR
        SELECT 
            OBJECT_SCHEMA_NAME(ips.object_id) + '.' + OBJECT_NAME(ips.object_id) AS TableName,
            i.name AS IndexName,
            ips.avg_fragmentation_in_percent
        FROM sys.dm_db_index_physical_stats(DB_ID(@DBName), NULL, NULL, NULL, 'LIMITED') ips
        JOIN sys.indexes i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
        WHERE ips.avg_fragmentation_in_percent > @MinFragmentation
          AND i.name IS NOT NULL
          AND ips.page_count > 1000  -- 忽略小表
    
    OPEN idx_cursor
    FETCH NEXT FROM idx_cursor INTO @TableName, @IndexName, @Fragmentation
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
        IF @Fragmentation < @MaxFragmentation
            SET @SQL = 'ALTER INDEX [' + @IndexName + '] ON ' + @TableName + ' REORGANIZE'
        ELSE
            SET @SQL = 'ALTER INDEX [' + @IndexName + '] ON ' + @TableName + ' REBUILD'
        
        EXEC sp_executesql @SQL
        
        FETCH NEXT FROM idx_cursor INTO @TableName, @IndexName, @Fragmentation
    END
    
    CLOSE idx_cursor
    DEALLOCATE idx_cursor
END

-- 调度:每周日凌晨执行
-- EXEC dbo.IndexMaintenance 'YourDB', 5, 30

5.3 备份完整性自动校验

-- 作业:恢复演练(自动验证备份文件)
CREATE PROC dbo.ValidateBackup
AS
BEGIN
    DECLARE @BackupFile NVARCHAR(500)
    DECLARE @TestDBName NVARCHAR(128)
    DECLARE @SQL NVARCHAR(MAX)
    
    -- 获取最新的完整备份
    SELECT TOP 1 @BackupFile = physical_device_name
    FROM msdb.dbo.backupset b
    JOIN msdb.dbo.backupmediafamily m ON b.media_set_id = m.media_set_id
    WHERE b.type = 'D' AND b.database_name = 'YourDB'
    ORDER BY b.backup_finish_date DESC
    
    -- 创建测试数据库名
    SET @TestDBName = 'YourDB_Validation_' + CONVERT(NVARCHAR, GETDATE(), 112)
    
    -- 恢复验证
    SET @SQL = '
        RESTORE DATABASE ' + @TestDBName + ' 
        FROM DISK = ''' + @BackupFile + '''
        WITH MOVE ''YourDB_Data'' TO ''D:\Test\' + @TestDBName + '.mdf'',
             MOVE ''YourDB_Log'' TO ''E:\Test\' + @TestDBName + '.ldf'',
             REPLACE, STATS=10
    '
    
    BEGIN TRY
        EXEC sp_executesql @SQL
        
        -- 校验完整性
        SET @SQL = 'DBCC CHECKDB(' + @TestDBName + ') WITH NO_INFOMSGS'
        EXEC sp_executesql @SQL
        
        -- 清理测试数据库
        SET @SQL = 'DROP DATABASE ' + @TestDBName
        EXEC sp_executesql @SQL
        
        -- 记录成功
        INSERT INTO DBA_ValidationLog (DatabaseName, BackupFile, Status, ValidateDate)
        VALUES ('YourDB', @BackupFile, 'SUCCESS', GETDATE())
    END TRY
    BEGIN CATCH
        -- 记录失败
        INSERT INTO DBA_ValidationLog (DatabaseName, BackupFile, Status, ErrorMsg, ValidateDate)
        VALUES ('YourDB', @BackupFile, 'FAILED', ERROR_MESSAGE(), GETDATE())
        
        -- 发送告警
        EXEC msdb.dbo.sp_send_dbmail
            @recipients = 'dba@company.com',
            @subject = '备份验证失败',
            @body = ERROR_MESSAGE()
    END CATCH
END

六、监控与维护

6.1 作业监控

-- 查看作业执行历史
SELECT 
    sj.name AS JobName,
    sh.run_date,
    sh.run_time,
    sh.run_duration,
    CASE sh.run_status
        WHEN 0 THEN 'Failed'
        WHEN 1 THEN 'Succeeded'
        WHEN 2 THEN 'Retry'
        WHEN 3 THEN 'Cancelled'
        WHEN 4 THEN 'In Progress'
    END AS Status,
    sh.message
FROM msdb.dbo.sysjobs sj
JOIN msdb.dbo.sysjobhistory sh ON sj.job_id = sh.job_id
WHERE sh.run_date >= CONVERT(INT, CONVERT(VARCHAR, DATEADD(day, -7, GETDATE()), 112))
ORDER BY sh.run_date DESC, sh.run_time DESC

-- 查看作业失败统计
SELECT 
    sj.name,
    COUNT(*) AS FailureCount,
    MAX(sh.run_date) AS LastFailureDate
FROM msdb.dbo.sysjobs sj
JOIN msdb.dbo.sysjobhistory sh ON sj.job_id = sh.job_id
WHERE sh.run_status = 0  -- Failed
  AND sh.run_date >= CONVERT(INT, CONVERT(VARCHAR, DATEADD(day, -30, GETDATE()), 112))
GROUP BY sj.name
ORDER BY FailureCount DESC

-- 检查长时间运行的作业
SELECT 
    sj.name,
    sh.run_date,
    sh.run_time,
    sh.run_duration,
    sh.run_duration/10000 AS Hours,
    (sh.run_duration%10000)/100 AS Minutes,
    (sh.run_duration%100) AS Seconds
FROM msdb.dbo.sysjobs sj
JOIN msdb.dbo.sysjobhistory sh ON sj.job_id = sh.job_id
WHERE sh.run_status = 1  -- Succeeded
  AND sh.run_duration > 360000  -- 超过1小时(3600秒)
ORDER BY sh.run_duration DESC

6.2 自动化运维检查清单

每日自动化

  • 数据库备份验证作业
  • 磁盘空间检查与告警
  • 失败作业重试机制
  • 数据库完整性检查(CHECKDB)

每周自动化

  • 索引维护(重建/重组)
  • 统计信息更新
  • 备份文件清理
  • 错误日志轮转

每月自动化

  • 备份恢复演练
  • 性能基线对比
  • 过期历史数据清理
  • 安全审计报告

七、核心总结

知识点核心要点
SQL Agent 作业定时执行 T-SQL/PowerShell/CmdExec 任务
步骤控制on_success_action / on_fail_action 控制流程
调度配置频率、间隔、起止时间灵活配置
操作员邮件/寻呼通知接收人
警报基于错误号/严重级/性能条件的自动告警
多服务器管理主服务器统一分发作业到目标服务器
数据库邮件必须配置才能发送告警邮件

一句话记住本期内容

SQL Agent 是 DBA 的自动化引擎——作业定任务,调度定时间,操作员定通知,多服务器定范围,把重复劳动交给机器。

动手练习

-- 场景:你需要管理 20 台 SQL Server,需要每天执行以下任务:
-- - 凌晨 2:00 完整备份所有用户数据库
-- - 凌晨 3:00 更新统计信息
-- - 每小时检查死锁(错误号 1205)
-- - 磁盘空间低于 10% 时自动告警

-- 问题1:如何实现统一管理 20 台服务器的作业?

-- 问题2:如何确保备份失败时立即通知 DBA?

-- 问题3:如何避免作业日志无限增长?
点击查看参考答案

问题1:配置多服务器管理。设置一台主服务器(MSX),其他 20 台作为目标服务器(TSX),在主服务器上创建作业并分发到所有目标服务器。

问题2

-- 在作业中配置通知
EXEC dbo.sp_update_job
    @job_name = N'DailyBackup',
    @notify_level_email = 2,  -- 失败时发送邮件
    @notify_email_operator_name = N'DBA_Team';

问题3:设置作业历史保留期限

-- 设置只保留7天历史
EXEC msdb.dbo.sp_set_sqlagent_properties
    @jobhistory_max_rows = 10000,
    @jobhistory_max_rows_per_job = 100;

下一期预告

性能监控与调优——DMV 与性能计数器的实战应用

  • 核心 DMV 查询模板
  • 性能计数器解读
  • 基线建立与异常检测
  • 等待统计深度分析
  • 自动化性能报告

📌 本文代码适用于 SQL Server 2016-2022。多服务器管理需要所有服务器能互相通信且使用相同的 SQL Agent 账户权限。

管理系列持续更新中,点击关注不错过第六期。