0

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

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

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

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

4

2 回答 2

1

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 个作业。

于 2009-10-28T09:40:18.253 回答
0

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

谢谢,安多马尔,质疑这个。事实证明,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 是有风险的,但这就是 Job Activity Monitor 使用的 - 我在 Profiler 上运行它 - 所以如果它发生变化,他们可能会提供一些其他方式来查找此信息。只要您将此代码包装在一个函数或 proc 中并记录您对它的依赖,这对我来说似乎是许多弊端中最小的一个。

于 2009-10-28T19:40:30.007 回答