您的位置:首页 > 其它

获取指定时间区间作业运行情况

2014-07-22 21:32 134 查看
背景:数据库服务器定期重启,想知道重启期间对作业的影响。通俗点就是服务器在重启这段时间,有哪些作业计划要运行,重启后是否要手动执行这些作业?
第一次重启的时候,按照最笨的方式,把所有作业看一遍,然后人为判断有哪些作业将受到影响,再根据作业具体代码,确定是否需手动执行。后来老大说要弄个过程出来,通过传入起止时间参数,返回区间内的作业计划。
PS:参考各类资料,修改过很多遍,最后成型在6月初,很多细节上的修改自己也记不清楚了,一直懒得整理。先放上代码,以及效果图。

/************************************************************
* 说明:输入将来的起、止时间,得到时间区间内作业计划情况。主要包括:
区间内首次执行时间、区间内末次执行时间、区间内执行次数、循环间隔、每天执行频率等。
* 使用:DBA_Pro_GetJobSchedules '20140612 07:00:00.000','20140612 08:00:00.000'
* 补充:手动运行作业,不会影响作业的计划调度。
************************************************************/
CREATE PROC DBA_Pro_GetJobSchedules
@Starttime DATETIME,
@Endtime DATETIME
AS

DECLARE @Midtime DATETIME
IF (@Starttime < GETDATE() OR @Starttime >= @Endtime)
BEGIN
PRINT('请输入将来的起、止时间,且开始时间小于结束时间!')
RETURN
END

CREATE TABLE #RunningJobs
(
name                        VARCHAR(128)--作业名称
,schedule_id                 INT--调度id
,next_scheduled_run_date     DATETIME--下次运行时间 yyyy-mm-dd hh:mi:ss:mmm
,active_start_time           DATETIME--执行间隔:开始时间 yyyy-mm-dd hh:mi:ss:mmm
,active_end_time             DATETIME--执行间隔:结束时间 yyyy-mm-dd hh:mi:ss:mmm
,starttime                   DATETIME--运行区间开始时间,比较传入的@Starttime和active_start_time,取大者
,endtime                     DATETIME--运行区间结束时间,比较传入的@Endtime和active_end_time,取小者
,daystatus                   INT--日期状态,用于标记当天是否满足作业运行日期,为0时当天将运行
,timestaus                   INT--时间状态,用于标记当天只执行一次的作业是否已运行,为0时当天将运行
)

WHILE (@Starttime < @Endtime)
BEGIN
SELECT @Midtime = CASE
WHEN DATEADD(DAY ,1 ,@Starttime) > @Endtime THEN @Endtime
ELSE CONVERT(VARCHAR ,DATEADD(DAY ,1 ,@starttime) ,112)
END

INSERT INTO #RunningJobs
SELECT sj.name
,scd.schedule_id
,c.next_scheduled_run_date
,CONVERT(
DATETIME
,CONVERT(VARCHAR(10) ,@Starttime ,120) + ' ' +
STUFF(
STUFF(RIGHT('000000' + CAST([active_start_time] AS VARCHAR(6)) ,6),3,0,':')
,6,0,':'
)
) [active_start_time]
,CONVERT(
DATETIME
,CONVERT(VARCHAR(10) ,@Starttime ,120) + ' ' +
STUFF(
STUFF(RIGHT('000000' + CAST([active_end_time] AS VARCHAR(6)) ,6),3,0,':')
,6,0,':'
)
) [active_end_time]
,CASE
WHEN @Starttime <
CONVERT(
DATETIME
,CONVERT(VARCHAR(10) ,@Starttime ,120) + ' ' +
STUFF(
STUFF(RIGHT('000000' + CAST([active_start_time] AS VARCHAR(6)) ,6),3,0,':')
,6,0,':'
)
) THEN CONVERT(
DATETIME
,CONVERT(VARCHAR(10) ,@Starttime ,120) + ' ' +
STUFF(
STUFF(RIGHT('000000' + CAST([active_start_time] AS VARCHAR(6)) ,6),3,0,':')
,6,0,':'
)
)
ELSE @Starttime
END     starttime
,CASE
WHEN @Midtime >
CONVERT(
DATETIME
,CONVERT(VARCHAR(10) ,@Starttime ,120) + ' ' +
STUFF(
STUFF(RIGHT('000000' + CAST([active_end_time] AS VARCHAR(6)) ,6),3,0,':')
,6,0,':'
)
) THEN CONVERT(
DATETIME
,CONVERT(VARCHAR(10) ,@Starttime ,120) + ' ' +
STUFF(
STUFF(RIGHT('000000' + CAST([active_end_time] AS VARCHAR(6)) ,6),3,0,':')
,6,0,':'
)
)
ELSE @Midtime
END     endtime
,CASE freq_type
WHEN 1 --OneTime
THEN DATEDIFF(day ,next_scheduled_run_date ,@Starttime)
WHEN 4 --Daily
THEN DATEDIFF(dd ,next_scheduled_run_date ,@Starttime)%freq_interval
WHEN 8 --Weekly
THEN DATEDIFF(week ,next_scheduled_run_date ,@Starttime)%freq_recurrence_factor
+
CASE
WHEN freq_interval & 1 = POWER(2 ,DATEPART(dw ,@Starttime) -1)
OR freq_interval & 2 = POWER(2 ,DATEPART(dw ,@Starttime) -1)
OR freq_interval & 4 = POWER(2 ,DATEPART(dw ,@Starttime) -1)
OR freq_interval & 8 = POWER(2 ,DATEPART(dw ,@Starttime) -1)
OR freq_interval & 16 = POWER(2 ,DATEPART(dw ,@Starttime) -1)
OR freq_interval & 32 = POWER(2 ,DATEPART(dw ,@Starttime) -1)
OR freq_interval & 64 = POWER(2 ,DATEPART(dw ,@Starttime) -1) THEN 0
END
WHEN 16 --Monthly
THEN DATEDIFF(MONTH ,next_scheduled_run_date ,@Starttime)%freq_recurrence_factor
+
CASE
WHEN freq_interval = DAY(@Starttime) THEN 0
END
WHEN 32 --Monthly - Relative to Frequency Interval
THEN DATEDIFF(MONTH ,next_scheduled_run_date ,@Starttime)%freq_recurrence_factor
+
CASE
WHEN freq_interval = DATEPART(dw ,@Starttime) --month of week1-7
AND
(
(
freq_relative_interval <= 8
AND freq_relative_interval = POWER(
2
,DATEDIFF(DAY ,CONVERT(CHAR(6) ,@Starttime ,112) + '01' ,@Starttime) / 7
)
)
OR (
freq_relative_interval = 16
AND DATEDIFF(
DAY
,@Starttime
,DATEADD(
DAY
,-1
,DATEADD(MONTH ,1 ,CONVERT(CHAR(6) ,@Starttime ,112) + '01')
)
) < 7
)
) THEN 0
WHEN freq_interval = 8 --month of day
AND

(
(
freq_relative_interval = 1
AND DATEDIFF(DAY ,CONVERT(CHAR(6) ,@Starttime ,112) + '01' ,@Starttime) = 0
)
OR (
freq_relative_interval = 2
AND DATEDIFF(DAY ,CONVERT(CHAR(6) ,@Starttime ,112) + '02' ,@Starttime) = 0
)
OR (
freq_relative_interval = 4
AND DATEDIFF(DAY ,CONVERT(CHAR(6) ,@Starttime ,112) + '03' ,@Starttime) = 0
)
OR (
freq_relative_interval = 8
AND DATEDIFF(DAY ,CONVERT(CHAR(6) ,@Starttime ,112) + '04' ,@Starttime) = 0
)
OR (
freq_relative_interval = 16
AND CONVERT(VARCHAR ,@Starttime ,112) =
CONVERT(
VARCHAR
,DATEADD(
DAY
,-1
,DATEADD(MONTH ,1 ,CONVERT(CHAR(6) ,@Starttime ,112) + '01')
)
,112
)
)
) THEN 0
WHEN freq_interval = 9 --month of weekday
AND
(
(
freq_relative_interval = 1
AND DATEADD(
DAY
,CASE DATEPART(dw ,CONVERT(CHAR(6) ,@Starttime ,112) + '01')
WHEN 1 THEN 1
WHEN 7 THEN 2
ELSE 0
END
,CONVERT(CHAR(6) ,@Starttime ,112) + '01'
) = CONVERT(VARCHAR ,@Starttime ,112)
)
OR (
freq_relative_interval = 2
AND DATEADD(
DAY
,CASE DATEPART(dw ,CONVERT(CHAR(6) ,@Starttime ,112) + '01')
WHEN 6 THEN 3
WHEN 7 THEN 3
WHEN 1 THEN 2
ELSE 1
END
,CONVERT(CHAR(6) ,@Starttime ,112) + '01'
) = CONVERT(VARCHAR ,@Starttime ,112)
)
OR (
freq_relative_interval = 4
AND DATEADD(
DAY
,CASE DATEPART(dw ,CONVERT(CHAR(6) ,@Starttime ,112) + '01')
WHEN 5 THEN 4
WHEN 6 THEN 4
WHEN 7 THEN 4
WHEN 1 THEN 3
ELSE 2
END
,CONVERT(CHAR(6) ,@Starttime ,112) + '01'
) = CONVERT(VARCHAR ,@Starttime ,112)
)
OR (
freq_relative_interval = 8
AND DATEADD(
DAY
,CASE DATEPART(dw ,CONVERT(CHAR(6) ,@Starttime ,112) + '01')
WHEN 4 THEN 5
WHEN 5 THEN 5
WHEN 6 THEN 5
WHEN 7 THEN 5
WHEN 1 THEN 4
ELSE 3
END
,CONVERT(CHAR(6) ,@Starttime ,112) + '01'
) = CONVERT(VARCHAR ,@Starttime ,112)
)
OR (
freq_relative_interval = 16
AND DATEADD(
DAY
,CASE DATEPART(
dw
,DATEADD(
DAY
,-1
,DATEADD(MONTH ,1 ,CONVERT(CHAR(6) ,@Starttime ,112) + '01')
)
)
WHEN 1 THEN -2
WHEN 7 THEN -1
ELSE 0
END
,DATEADD(
DAY
,-1
,DATEADD(MONTH ,1 ,CONVERT(CHAR(6) ,@Starttime ,112) + '01')
)
) = CONVERT(VARCHAR ,@Starttime ,112)
)
) THEN 0
WHEN freq_interval = 10 --month of weekend
AND
(
(
freq_relative_interval = 1
AND DATEADD(
DAY
,CASE DATEPART(dw ,CONVERT(CHAR(6) ,@Starttime ,112) + '01')
WHEN 2 THEN 5
WHEN 3 THEN 4
WHEN 4 THEN 3
WHEN 5 THEN 2
WHEN 6 THEN 1
ELSE 0
END
,CONVERT(CHAR(6) ,@Starttime ,112) + '01'
) = CONVERT(VARCHAR ,@Starttime ,112)
)
OR (
freq_relative_interval = 2
AND DATEADD(
DAY
,CASE DATEPART(dw ,CONVERT(CHAR(6) ,@Starttime ,112) + '01')
WHEN 3 THEN 5
WHEN 4 THEN 4
WHEN 5 THEN 3
WHEN 6 THEN 2
WHEN 7 THEN 1
ELSE 6
END
,CONVERT(CHAR(6) ,@Starttime ,112) + '01'
) = CONVERT(VARCHAR ,@Starttime ,112)
)
OR (
freq_relative_interval = 4
AND DATEADD(
DAY
,CASE DATEPART(dw ,CONVERT(CHAR(6) ,@Starttime ,112) + '01')
WHEN 2 THEN 12
WHEN 3 THEN 11
WHEN 4 THEN 10
WHEN 5 THEN 9
WHEN 6 THEN 8
ELSE 7
END
,CONVERT(CHAR(6) ,@Starttime ,112) + '01'
) = CONVERT(VARCHAR ,@Starttime ,112)
)
OR (
freq_relative_interval = 8
AND DATEADD(
DAY
,CASE DATEPART(dw ,CONVERT(CHAR(6) ,@Starttime ,112) + '01')
WHEN 3 THEN 12
WHEN 4 THEN 11
WHEN 5 THEN 10
WHEN 6 THEN 9
WHEN 7 THEN 8
ELSE 13
END
,CONVERT(CHAR(6) ,@Starttime ,112) + '01'
) = CONVERT(VARCHAR ,@Starttime ,112)
)
OR (
freq_relative_interval = 16
AND DATEADD(
DAY
,CASE DATEPART(
dw
,DATEADD(
DAY
,-1
,DATEADD(MONTH ,1 ,CONVERT(CHAR(6) ,@Starttime ,112) + '01')
)
)
WHEN 2 THEN -1
WHEN 3 THEN -2
WHEN 4 THEN -3
WHEN 5 THEN -4
WHEN 6 THEN -5
ELSE 0
END
,DATEADD(
DAY
,-1
,DATEADD(MONTH ,1 ,CONVERT(CHAR(6) ,@Starttime ,112) + '01')
)
) = CONVERT(VARCHAR ,@Starttime ,112)
)
) THEN 0
END
END  AS daystatus
,CASE
WHEN freq_subday_type IN (0 ,1)
THEN
CASE
WHEN active_start_time*1000
>= CONVERT(INT ,REPLACE(CONVERT(VARCHAR ,@Starttime ,114) ,':' ,''))
THEN 0
ELSE 1
END
ELSE 0
END AS timestaus
FROM   [msdb].[dbo].[sysschedules] scd
INNER JOIN msdb.dbo.sysjobschedules sjsc
ON  scd.schedule_id = sjsc.schedule_id
INNER JOIN (
SELECT a.job_id
,a.next_scheduled_run_date
FROM   msdb.dbo.sysjobactivity a
INNER JOIN (
SELECT MAX(session_id) session_id
FROM   msdb.dbo.syssessions
) b
ON  a.session_id = b.session_id
) c
ON  sjsc.job_id = c.job_id
INNER JOIN msdb.dbo.sysjobs sj

ON  c.job_id = sj.job_id
WHERE  scd.enabled = 1
AND sj.enabled = 1
--AND c.next_scheduled_run_date <= @Midtime

SET @Starttime = CONVERT(VARCHAR ,DATEADD(DAY ,1 ,@starttime) ,112)
END
--select * from #RunningJobs order by name,active_start_time
SELECT name--作业名称
,plan_type--计划类型
,frequency--执行频率每天、每周、每月
,next_scheduled_run_date--下次计划运行时间
,FirstRunTimeInRange--区间内首次运行时间
,LastRunTimeInRange--区间内末次运行时间
,RunTimesInRange--区间内运行次数
,intercycle--循环间隔
,execution_interval--每天执行频率及区间
,active_start_date--开始日期
,active_end_date--结束日期
,date_created--创建时间
,date_modified--修改时间
FROM   (
SELECT a.name
,a.schedule_id
,a.active_start_time
,a.starttime
,a.endtime
,freq_type,freq_subday_type
,freq_subday_interval
,CASE
WHEN [freq_type] = 64 THEN
'Start automatically when SQL Server Agent starts'
WHEN [freq_type] = 128 THEN
'Start whenever the CPUs become idle'
WHEN [freq_type] IN (4 ,8 ,16 ,32) THEN 'Recurring'
WHEN [freq_type] = 1 THEN 'One Time'
END                    AS plan_type
,CASE [freq_type]
WHEN 1 THEN 'One Time'
WHEN 4 THEN 'Daily'
WHEN 8 THEN 'Weekly'
WHEN 16 THEN 'Monthly'
WHEN 32 THEN 'Monthly - Relative to Frequency Interval'
WHEN 64 THEN 'Start automatically when SQL Server Agent starts'
WHEN 128 THEN 'Start whenever the CPUs become idle'
END                    AS frequency
,a.next_scheduled_run_date
,CASE [freq_subday_type]
WHEN 2 THEN DATEADD(
second
,(
freq_subday_interval -
DATEDIFF(second ,a.active_start_time ,a.starttime)
%freq_subday_interval
)%freq_subday_interval
,a.starttime
)
WHEN 4 THEN DATEADD(
second
,(
freq_subday_interval * 60 -
DATEDIFF(second ,a.active_start_time ,a.starttime)
%(freq_subday_interval * 60)
)%(freq_subday_interval * 60)
,a.starttime
)
WHEN 8 THEN DATEADD(
second
,(
freq_subday_interval * 3600 -
DATEDIFF(second ,a.active_start_time ,a.starttime)
%(freq_subday_interval * 3600)
)%(freq_subday_interval * 3600)
,a.starttime
)
ELSE a.active_start_time
END                    AS FirstRunTimeInRange
,CASE [freq_subday_type]
WHEN 2 THEN DATEADD(
second
,-DATEDIFF(second ,a.active_start_time ,a.endtime)
%freq_subday_interval
,a.endtime
)
WHEN 4 THEN DATEADD(
second
,-DATEDIFF(second ,a.active_start_time ,a.endtime)
%(freq_subday_interval * 60)
,a.endtime
)
WHEN 8 THEN DATEADD(
second
,-DATEDIFF(second ,a.active_start_time ,a.endtime)
%(freq_subday_interval * 3600)
,a.endtime
)
ELSE a.active_start_time
END                    AS LastRunTimeInRange
,CASE [freq_subday_type]
WHEN 2 THEN DATEDIFF(
second
,DATEADD(
second
,(
freq_subday_interval -
DATEDIFF(second ,a.active_start_time ,a.starttime)
%freq_subday_interval
)%freq_subday_interval
,a.starttime
)
,a.endtime
) / (freq_subday_interval) + 1
WHEN 4 THEN DATEDIFF(
second
,DATEADD(
second
,(
freq_subday_interval * 60 -
DATEDIFF(second ,a.active_start_time ,a.starttime)
%(freq_subday_interval * 60)
)%(freq_subday_interval * 60)
,a.starttime
)
,a.endtime
) / (freq_subday_interval * 60) + 1
WHEN 8 THEN DATEDIFF(
second
,DATEADD(
second
,(
freq_subday_interval * 3600 -
DATEDIFF(second ,a.active_start_time ,a.starttime)
%(freq_subday_interval * 3600)
)%(freq_subday_interval * 3600)
,a.starttime
)
,a.endtime
) / (freq_subday_interval * 3600) + 1
ELSE 1
END                    AS RunTimesInRange
,CASE [freq_type]
WHEN 4 THEN 'Occurs every ' + CAST([freq_interval] AS VARCHAR(3))
+ ' day(s)'
WHEN 8 THEN 'Occurs every ' + CAST([freq_recurrence_factor] AS VARCHAR(3))
+ ' week(s) on '
+ CASE
WHEN [freq_interval] & 1 = 1 THEN 'Sunday'
ELSE ''
END
+ CASE
WHEN [freq_interval] & 2 = 2 THEN ', Monday'
ELSE ''
END
+ CASE
WHEN [freq_interval] & 4 = 4 THEN ', Tuesday'
ELSE ''
END
+ CASE
WHEN [freq_interval] & 8 = 8 THEN ', Wednesday'
ELSE ''
END
+ CASE
WHEN [freq_interval] & 16 = 16 THEN ', Thursday'
ELSE ''
END
+ CASE
WHEN [freq_interval] & 32 = 32 THEN ', Friday'
ELSE ''
END
+ CASE
WHEN [freq_interval] & 64 = 64 THEN ', Saturday'
ELSE ''
END
WHEN 16 THEN 'Occurs on Day ' + CAST([freq_interval] AS VARCHAR(3))
+ ' of every ' + CAST([freq_recurrence_factor] AS VARCHAR(3))
+ ' month(s)'
WHEN 32 THEN 'Occurs on ' + CASE [freq_relative_interval]
WHEN 1 THEN 'First'
WHEN 2 THEN 'Second'
WHEN 4 THEN 'Third'
WHEN 8 THEN 'Fourth'
WHEN 16 THEN 'Last'
END + ' ' + CASE
[freq_interval]
WHEN 1 THEN
'Sunday'
WHEN 2 THEN
'Monday'
WHEN 3 THEN
'Tuesday'
WHEN 4 THEN
'Wednesday'
WHEN 5 THEN
'Thursday'
WHEN 6 THEN
'Friday'
WHEN 7 THEN
'Saturday'
WHEN 8 THEN
'Day'
WHEN 9 THEN
'Weekday'
WHEN 10 THEN
'Weekend day'
END +
' of every '
+ CAST([freq_recurrence_factor] AS VARCHAR(3)) +
' month(s)'
END                    AS intercycle
,CASE [freq_subday_type]
WHEN 1 THEN 'Occurs once at ' + CONVERT(VARCHAR ,a.active_start_time ,108)
WHEN 2 THEN 'Occurs every ' + CAST([freq_subday_interval] AS VARCHAR(3))
+ ' Second(s) between ' + CONVERT(VARCHAR ,a.active_start_time ,108)
+ ' and ' + CONVERT(VARCHAR ,a.active_end_time ,108)
WHEN 4 THEN 'Occurs every ' + CAST([freq_subday_interval] AS VARCHAR(3))
+ ' Minute(s) between ' + CONVERT(VARCHAR ,a.active_start_time ,108)
+ ' and ' + CONVERT(VARCHAR ,a.active_end_time ,108)
WHEN 8 THEN 'Occurs every ' + CAST([freq_subday_interval] AS VARCHAR(3))
+ ' Hour(s) between ' + CONVERT(VARCHAR ,a.active_start_time ,108)
+ ' and ' + CONVERT(VARCHAR ,a.active_end_time ,108)
END                    AS execution_interval
,STUFF(
STUFF(CAST([active_start_date] AS VARCHAR(8)) ,5 ,0 ,'-')
,8,0,'-'
)                      AS active_start_date
,STUFF(
STUFF(CAST([active_end_date] AS VARCHAR(8)) ,5 ,0 ,'-')
,8,0,'-'
)                      AS active_end_date
,scd.[date_created] AS date_created
,scd.[date_modified] AS date_modified
FROM   #RunningJobs a
INNER JOIN [msdb].[dbo].[sysschedules] scd
ON  a.schedule_id = scd.schedule_id
WHERE  a.daystatus = 0
AND a.timestaus=0
) a
WHERE  a.FirstRunTimeInRange <= a.endtime
AND a.FirstRunTimeInRange <= CONVERT(DATETIME ,a.active_end_date + ' 23:59:59:997')
ORDER BY
a.name
,a.FirstRunTimeInRange

DROP TABLE #RunningJobs


View Code
执行过程将返回作业区间内首次执行时间、区间内末次执行时间、区间内执行次数、循环间隔、每天执行频率等信息


--15:31 2015/1/14 如果我们想把一个操作加到某个00:00:00执行作业的最后一步,我们先要把零点的那些作业找出来,此时可以利用msdb.dbo.sysjobschedules查询作业下次执行时间。注意msdb.dbo.sysjobschedules由后台线程每20分钟更新一次。

--下次执行时间(后台线程每20分钟更新)
select top 5 sj.name,sjs.next_run_date,sjs.next_run_time from msdb.dbo.sysjobs sj
inner join msdb.dbo.sysjobschedules sjs
on sj.job_id=sjs.job_id
where sj.enabled=1
and next_run_time=0--根据需求调整
order by sjs.next_run_date,sjs.next_run_time


对于执行频率很高的作业,msdb.dbo.sysjobschedules中的下次运行时间会滞后,如果需要实时的信息可以从msdb.dbo.sysjobactivity中获取。SQL Server代理服务每次重启后,将创建一个新的会话,并且 msdb 数据库的 sysjobactivity 表由所有现有的已定义作业填充。

--下次执行时间(实时更新)
select top 5 sj.name,sja.next_scheduled_run_date from msdb.dbo.sysjobs sj
inner join
(select * from msdb.dbo.sysjobactivity
where session_id in(select max(session_id) session_id from msdb.dbo.sysjobactivity)
)sja
on sj.job_id=sja.job_id
where sj.enabled=1
order by sja.next_scheduled_run_date


实时更新的代码对应“SQL Server 代理->作业活动监视器”的内容,里面可以设置筛选、排序。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐