SQL 代理作业 - 作为队列执行

发布于 2024-08-09 18:18:42 字数 230 浏览 7 评论 0原文

我有一个 SQL Server 作业正在使用 sp_start_job 调用其他 10 个作业。该作业有 10 个步骤,每个步骤都会再次调用子作业。

当我执行主要作业时,我可以看到它从步骤 1 开始,几秒钟后它显示“成功完成”。

但这些作业需要很长时间才能运行,当我验证日志信息时,它显示所有 10 个步骤在后面同时运行,直到几个小时后完成。

我的要求是它应该首先完成步骤 1,然后才开始步骤 2。

I have a SQL Server job which is calling 10 other jobs using sp_start_job. The job has 10 steps, each step is again calling sub jobs.

When I execute the main job, I can see it started with step 1 and in a few seconds it shows 'Finished Successfully'.

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.

My requirement is that it should finish step 1 first and only then step2 should start.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

三寸金莲 2024-08-16 18:18:42

Microsoft Code 论坛有一个检查存储过程是否正在运行的方法。您可以使用它来等待作业完成:

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

这样,代码的工作方式是等待 10 秒,然后检查作业 YourJobName 是否正在运行。它会重复此操作,直到作业不再运行。您可以将其放在 sp_start_job 调用之间。

话虽如此,肯定还有更简单的方法。不能将 10 个作业的代码分别存储在存储过程中吗? “主”作业可以调用 10 个存储过程,而不是启动这 10 个作业。

The Microsoft Code forum has a way to check if a stored procedure is running. 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. It repeats that until the job is no longer running. You could put this in between the sp_start_job calls.

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? The "master" job could call the 10 stored procedures, instead of starting the 10 jobs.

ゝ杯具 2024-08-16 18:18:42

我的第一个答案是,您可以使用上面的循环,但检查 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

谢谢,Andomar,对此提出质疑。事实证明,sysjobhistory 仅在第一步完成后才会更新。只有白痴才会想象,如果 run_status 的一个值为“进行中”,则在步骤开始时必须更新表!我查了一下,这似乎是一个棘手的问题。 SQL 知道某个地方发生了什么,但它并没有很好地公开信息。

看来您必须在数英里的复杂代码或使用未记录的存储过程之间做出选择。通过谷歌搜索 sysjobhistory,您可以轻松找到数英里长的代码答案(有好几个)。就我个人而言,我更喜欢 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

我已经测试过这个方法,它似乎确实有效。也许使用这个xp有风险,但这就是作业活动监视器使用的东西——我在Profiler打开的情况下运行它——所以如果它发生变化,他们可能会提供一些其他方式来查找此信息。只要您将此代码包装在函数或过程中并记录您对它的依赖,对我来说这似乎是众多邪恶中最小的一个。

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:

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. It turns out that sysjobhistory is only updated once the first step has completed. Only an idiot would imagine that, if one value of run_status is 'In progress', the table must be updated when a step starts! 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.

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. Personally I prefer the xp approach:

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. 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文