简体   繁体   English

SQL Agent Job-作为队列执行

[英]SQL Agent Job - to execute as queue

I have a SQL Server job which is calling 10 other jobs using sp_start_job. 我有一个SQL Server作业,正在使用sp_start_job调用其他10个作业。 The job has 10 steps, each step is again calling sub jobs. 该作业有10个步骤,每个步骤再次调用子作业。

When I execute the main job, I can see it started with step 1 and in a few seconds it shows 'Finished Successfully'. 执行主作业时,我可以看到它从步骤1开始,然后在几秒钟内显示“已成功完成”。

But the jobs take a long time time to run, and when I verify the logging information, it shows the all the 10 steps are running simultaneously at the back, until it finishes after few hours. 但是作业要花很长时间才能运行,当我验证日志记录信息时,它显示了所有10个步骤同时在后面运行,直到几个小时后完成。

My requirement is that it should finish step 1 first and only then step2 should start. 我的要求是它应该首先完成步骤1,然后才应该开始步骤2。

The Microsoft Code forum has a way to check if a stored procedure is running. Microsoft Code论坛提供了一种检查存储过程是否正在运行的方法。 You could use that to wait until the job is complete: 您可以使用它来等待作业完成:

while 1=1
    begin
    WAITFOR DELAY '000:00:10'

    if not exists (
        SELECT *
        FROM master..sysprocesses p
        JOIN msdb..sysjobs j ON 
            substring(left(j.job_id,8),7,2) + 
            substring(left(j.job_id,8),5,2) +
            substring(left(j.job_id,8),3,2) + 
            substring(left(j.job_id,8),1,2) =
            substring(p.program_name,32,8)
        WHERE j.name = 'YourJobName'
        AND program_name like 'SQLAgent - TSQL JobStep (Job %'
    )
        break
    end

This way the code works is that it waits for 10 seconds, then checks if the job YourJobName is running. 这种代码的工作方式是等待10秒钟,然后检查作业YourJobName是否正在运行。 It repeats that until the job is no longer running. 重复该操作,直到作业不再运行。 You could put this in between the sp_start_job calls. 您可以将其放在sp_start_job调用之间。

Having said that, there must be an easier way. 话虽如此,必须有一种更简单的方法。 Can't you store the code for each of the 10 jobs in a stored procedure? 您不能在存储过程中存储10个作业中每个作业的代码吗? The "master" job could call the 10 stored procedures, instead of starting the 10 jobs. “主”作业可以调用10个存储过程,而不是启动10个作业。

My first answer was that you could use a loop as above but check the job history tables in msdb to wait for the preceding job to finish: 我的第一个答案是,您可以使用上述循环,但是请检查msdb中的作业历史记录表以等待上一个作业完成:

select  sj.name as job_name
from    msdb.dbo.sysjobhistory sjh
    inner join msdb.dbo.sysjobs_view sj on sj.job_id = sjh.job_id
where   sjh.step_id = 0 --Job outcome
    and sjh.run_status = 4 --In progress

Thanks, Andomar, for questioning this. 谢谢Andomar对此提出质疑。 It turns out that sysjobhistory is only updated once the first step has completed. 事实证明,仅在第一步完成后才更新sysjobhistory。 Only an idiot would imagine that, if one value of run_status is 'In progress', the table must be updated when a step starts! 只有白痴才能想象,如果run_status的一个值是'In progress',则必须在步骤开始时更新表! I've searched around and this seems to be a tough issue. 我四处搜寻,这似乎是个棘手的问题。 Somewhere SQL knows what's going on but it doesn't expose the information very well. SQL在某个地方知道发生了什么,但是并不能很好地揭示信息。

It seems you have to choose between miles of complicated code or using an undocumented stored proc. 似乎您必须在数英里的复杂代码之间进行选择,或者使用未记录的存储过程进行选择。 You can easily find the miles of code answers - there are several - by Googling for sysjobhistory. 您可以通过Googling轻松找到sysjobhistory的英里数的代码答案。 Personally I prefer the xp approach: 我个人更喜欢使用xp方法:

create table #xp_results(
    job_id uniqueidentifier not null,
    last_run_date int not null,
    last_run_time int not null,
    next_run_date int not null,
    next_run_time int not null,
    next_run_schedule_id int not null,
    requested_to_run int not null, -- bool
    request_source int not null,
    request_source_id sysname collate database_default null,
    running int not null, -- bool
    current_step int not null,
    current_retry_attempt int not null,
    job_state int not null )

insert #xp_results exec master.dbo.xp_sqlagent_enum_jobs @is_sysadmin = 1, @job_owner = ''

select  sj.name
from    #xp_results xpr
    inner join msdb.dbo.sysjobs_view sj on sj.job_id = xpr.job_id
where running = 1

drop table #xp_results

I've tested this and it really does seem to work. 我已经测试过了,它确实确实起作用了。 Perhaps it's risky using this xp but that's what the Job Activity Monitor uses - I ran it with the Profiler on - so if it changes they'll probably provide some other way to find this info. 也许使用此xp会有风险,但这是作业活动监视器使用的-我在Profiler开启的情况下运行了它-因此,如果更改,它们可能会提供一些其他方式来查找此信息。 As long as you wrap this code up in a function or proc and document that you have a dependency on it, it seems like the least of many evils to me. 只要将这段代码包装在一个函数或proc中,并记录对它的依赖关系,对我来说,这似乎是最少的麻烦。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM