3. 作业创建与配置实战

SQL Server 代理作业(SQL Server Agent Job)是自动化运维的核心执行单元。一个作业由若干“步骤”组成,步骤之间通过“成功流”和“失败流”决定执行顺序;作业还可以把每个步骤的输出写入操作系统文件,并把执行历史保存在 msdb 系统库中。本节以“每日凌晨 2:00 对业务库执行索引维护并记录结果”为例,分别用 SSMS 图形界面和 T-SQL 脚本完成创建与配置,重点讲清步骤、控制流、输出文件和历史记录四件事。

一、先明确作业的四个组成要素

在动手之前,需要先建立对象模型:作业本身只承载名称、所有者、分类、启用状态和调度;真正干活的是步骤;步骤之间的先后关系由“成功时转到第几步 / 失败时转到第几步”决定;输出文件和历史记录则负责留痕。理解这四层关系,后面的配置就不会乱。

SQL Server 代理作业结构关系 作业 Job 名称/所有者/分类/启用 调度 Schedule 每日 02:00 步骤 Step T-SQL / CmdExec / SSIS 成功流 / 失败流 OnSuccess / OnFailure 输出文件 Output File C:\JobLog\IndexMaint.txt 历史记录 msdb sysjobhistory 步骤控制流示例(3 个步骤) 1 重建索引 成功→2 失败→3 2 更新统计信息 成功→退出 失败→3 3 发送告警 成功→退出

二、用 SSMS 创建作业

在对象资源管理器中展开“SQL Server 代理”,右键“作业”→“新建作业”,打开“新建作业”对话框。该对话框左侧有“常规、步骤、计划、警报、通知、目标”六个页面,本节只涉及前三个。

常规页:填写名称 DBA_IndexMaintenance_Daily,所有者保持 sa 或专用运维账号,分类选择“数据库维护”,勾选“已启用”。

步骤页:点击“新建”,弹出“新建作业步骤”窗口。步骤名填 1_RebuildIndex,类型选“Transact-SQL 脚本(T-SQL)”,数据库选 BizDB,命令框输入:

SET NOCOUNT ON;
ALTER INDEX ALL ON dbo.Orders
    REBUILD WITH (ONLINE = ON, MAXDOP = 4);
PRINT 'RebuildIndex finished at ' + CONVERT(varchar(19), GETDATE(), 120);

切到“高级”页,这里就是控制流和输出文件的关键位置:

  • “成功时要执行的操作”:选择“转到下一步”,即成功后进入步骤 2。
  • “失败时要执行的操作”:选择“转到步骤”,并指定第 3 步,即失败时跳过统计信息更新,直接告警。
  • “重试次数”设为 1,“重试间隔(分钟)”设为 2,用于应对偶发的锁等待。
  • “输出文件”勾选“将输出追加到现有文件”,路径填 C:\JobLog\IndexMaint.txt。

按同样方式新建步骤 2 2_UpdateStatistics,命令为 UPDATE STATISTICS dbo.Orders WITH FULLSCAN;,成功时“退出报告成功的作业”,失败时“转到步骤 3”。步骤 3 3_SendAlert 类型选“操作系统(CmdExec)”,命令用 sqlcmd 或 powershell 发送邮件,成功时退出。

计划页:点击“新建”,频率选“每天”,执行时间 02:00:00,持续时间“无结束日期”。保存后作业即处于启用状态。

输出文件目录必须提前创建,且 SQL Server 代理服务账户(默认 NT SERVICE\SQLSERVERAGENT)对该目录要有写权限,否则步骤会因无法写入而失败。

三、用 T-SQL 创建同样的作业

图形界面适合一次性配置,批量部署和版本化则更适合脚本。核心存储过程是 msdb.dbo.sp_add_job、sp_add_jobstep、sp_add_jobschedule 和 sp_add_jobserver。

USE msdb;
GO
EXEC dbo.sp_add_job
     @job_name = N'DBA_IndexMaintenance_Daily',
     @enabled  = 1,
     @description = N'每日索引维护与统计信息更新';

EXEC dbo.sp_add_jobstep
     @job_name       = N'DBA_IndexMaintenance_Daily',
     @step_id        = 1,
     @step_name      = N'1_RebuildIndex',
     @subsystem      = N'TSQL',
     @database_name  = N'BizDB',
     @command        = N'ALTER INDEX ALL ON dbo.Orders REBUILD WITH (ONLINE=ON, MAXDOP=4);',
     @on_success_action = 3,   -- 3 = 转到下一步
     @on_fail_action    = 4,   -- 4 = 转到指定步骤
     @on_fail_step_id   = 3,
     @retry_attempts    = 1,
     @retry_interval    = 2,
     @output_file_name  = N'C:\JobLog\IndexMaint.txt',
     @flags             = 2;   -- 2 = 追加到现有文件

EXEC dbo.sp_add_jobstep
     @job_name       = N'DBA_IndexMaintenance_Daily',
     @step_id        = 2,
     @step_name      = N'2_UpdateStatistics',
     @subsystem      = N'TSQL',
     @database_name  = N'BizDB',
     @command        = N'UPDATE STATISTICS dbo.Orders WITH FULLSCAN;',
     @on_success_action = 1,   -- 1 = 退出报告成功
     @on_fail_action    = 4,
     @on_fail_step_id   = 3;

EXEC dbo.sp_add_jobstep
     @job_name       = N'DBA_IndexMaintenance_Daily',
     @step_id        = 3,
     @step_name      = N'3_SendAlert',
     @subsystem      = N'CmdExec',
     @command        = N'powershell.exe -File C:\Scripts\SendAlert.ps1',
     @on_success_action = 1,
     @on_fail_action    = 2;   -- 2 = 退出报告失败

EXEC dbo.sp_add_schedule
     @schedule_name = N'Daily_0200',
     @freq_type     = 4,       -- 4 = 每天
     @freq_interval = 1,
     @active_start_time = 20000;

EXEC dbo.sp_attach_schedule
     @job_name = N'DBA_IndexMaintenance_Daily',
     @schedule_name = N'Daily_0200';

EXEC dbo.sp_add_jobserver
     @job_name = N'DBA_IndexMaintenance_Daily';

其中 @on_success_action 与 @on_fail_action 的取值需要记牢:1 退出报告成功,2 退出报告失败,3 转到下一步,4 转到指定步骤。这正是图形界面“成功流/失败流”背后的参数。

四、输出文件与历史记录

输出文件保存的是步骤运行时控制台产生的文本,包括 PRINT 输出、错误信息和影响行数,适合排查细节。历史记录则保存在 msdb.dbo.sysjobhistory,记录每次运行的步骤、状态、开始时间、耗时和消息。查询最近一次执行结果:

SELECT TOP 10
       j.name AS job_name,
       h.step_id,
       h.step_name,
       h.run_status,   -- 0失败 1成功 2重试 3取消 4进行中
       h.run_date,
       h.run_time,
       h.run_duration,
       h.message
FROM   msdb.dbo.sysjobhistory h
JOIN   msdb.dbo.sysjobs j ON j.job_id = h.job_id
WHERE  j.name = N'DBA_IndexMaintenance_Daily'
ORDER  BY h.run_date DESC, h.run_time DESC;

历史记录默认只保留一定条数,可在“SQL Server 代理属性”→“历史记录”页设置“每个作业的最大历史记录行数”和“最大历史记录行数”,也可用 sp_purge_jobhistory 手动清理。输出文件不会自动清理,需要配合维护计划或脚本定期归档,避免磁盘被日志撑满。

若步骤失败但作业仍显示成功,通常是失败流被设置成了“退出报告成功”。排查时先看 sysjobhistory.run_status,再核对每个步骤的 on_fail_action,不要只看作业整体状态。

五、验证与常见判断依据

配置完成后,右键作业选择“作业开始步骤”,手动执行一次。判断是否达成目标的依据有三条:一是作业历史中三个步骤的 run_status 是否按预期流转;二是输出文件是否按追加方式写入并包含时间戳;三是失败场景下是否真的跳到了步骤 3。可以故意把步骤 1 的表名改成不存在的对象,观察失败流是否生效,验证后再改回。这样一套“创建—配置—触发—看历史—看文件”的闭环,才是作业治理真正可复用的基础。