【问题标题】:How can I determine the status of a job?如何确定工作的状态?
【发布时间】:2010-09-17 01:03:22
【问题描述】:

我有一个调度作业的存储过程。这项工作需要很长时间才能完成(大约 30 到 40 分钟)。我需要了解这份工作的状态。 以下详细信息将对我有所帮助

1) 如何查看已安排在未来某个时间但尚未开始的所有作业的列表

2) 如何查看正在运行的作业列表以及从它们运行开始的时间跨度

3) 如何查看作业是否成功完成或因任何错误而停止。

【问题讨论】:

    标签: sql sql-server-2005 tsql stored-procedures


    【解决方案1】:

    您尚未指定希望如何查看这些详细信息。

    第一次看到我建议检查Server Management Studio

    您可以在 SQL Server 代理部分的作业下查看作业和当前状态。如果您选择了一个工作,“属性”页面会显示一个指向“工作历史记录”的链接,您可以在其中查看开始和结束时间、是否有任何错误、哪个步骤导致了错误等等。

    您可以指定警报和通知,以便在作业成功或失败时向您发送电子邮件或寻呼。

    有一个作业活动监视器,但实际上我从未使用过它。你可以试一试。

    如果你想通过T-SQL检查,那我不知道你该怎么做。

    【讨论】:

    • 在属性页面上没有指向历史记录的链接(至少在 2008 R2 中没有),您可能是指上下文菜单(右键单击作业时)
    • 属性窗口底部有一个“查看作业历史”链接。我在 2008 R2 上检查过。
    【解决方案2】:

    您可以尝试使用系统存储过程 sp_help_job。这将返回有关作业、其步骤、时间表和服务器的信息。例如

    EXEC msdb.dbo.sp_help_job @Job_name = 'Your Job Name'
    

    SQL Books Online 应该包含很多关于它返回的记录的信息。

    要返回多个作业的信息,您可以尝试查询以下系统表,这些表包含作业的各种信息

    • msdb.dbo.SysJobs
    • msdb.dbo.SysJobSteps
    • msdb.dbo.SysJobSchedules
    • msdb.dbo.SysJobServers
    • msdb.dbo.SysJobHistory

    它们的名称是不言自明的(除了保存有关作业上次运行时间和结果的信息的 SysJobServers)。

    同样,有关字段的信息可以在 MSDN 上找到。例如,查看SysJobs的页面

    【讨论】:

    • 需要表 msdb.dbo.sysjobactivity 来实际确定作业当前是否正在运行。表 msdb.dbo.sysjobhistory 显然仅在 一个作业(或一个步骤?)完成之后填充 - 并且对于“手动”启动的作业(即不是来自作业计划)根本不填充。
    • 如何知道实际的起始步骤是什么?
    • 这是一个非常笼统的答案。 @efesar 提出的解决方案确实有效。请考虑将其标记为答案next
    【解决方案3】:

    这是我用来获取正在运行的作业(主要是为了我可以杀死可能挂起的作业):

    SELECT
        job.Name, job.job_ID
        ,job.Originating_Server
        ,activity.run_requested_Date
        ,datediff(minute, activity.run_requested_Date, getdate()) AS Elapsed
    FROM
        msdb.dbo.sysjobs_view job 
            INNER JOIN msdb.dbo.sysjobactivity activity
            ON (job.job_id = activity.job_id)
    WHERE
        run_Requested_date is not null 
        AND stop_execution_date is null
        AND job.name like 'Your Job Prefix%'
    

    正如 Tim 所说,MSDN / BOL 文档在 sysjobsX 表的内容上相当不错。请记住,它们是 MSDB 中的表。

    【讨论】:

    • 如果要以编程方式使用此信息(例如,用于编写取决于作业是否正在运行的 T-SQL 代码),则此方法优于使用存储过程 msdb.dbo.sp_help_job 的使用。
    • 很难找出当前正在运行的作业的执行时间。我发现的所有脚本只包括作业上次运行的执行时间。这个答案是大海捞针。
    【解决方案4】:

    我们可以通过多种方式查询 msdb 以获取详细信息。

    很少

    select job.Name, job.job_ID, job.Originating_Server,activity.run_requested_Date,
    datediff(minute, activity.run_requested_Date, getdate()) as Elapsed 
    from msdb.dbo.sysjobs_view job 
    inner join msdb.dbo.sysjobactivity activity on (job.job_id = activity.job_id) 
    where run_Requested_date is not null 
    and stop_execution_date is null 
    and job.name like 'Your Job Prefix%'
    

    【讨论】:

      【解决方案5】:
      -- Microsoft SQL Server 2008 Standard Edition:
      IF EXISTS(SELECT 1 
                FROM msdb.dbo.sysjobs J 
                JOIN msdb.dbo.sysjobactivity A 
                    ON A.job_id=J.job_id 
                WHERE J.name=N'Your Job Name' 
                AND A.run_requested_date IS NOT NULL 
                AND A.stop_execution_date IS NULL
               )
          PRINT 'The job is running!'
      ELSE
          PRINT 'The job is not running.'
      

      【讨论】:

      • 我们的 sql server 崩溃了,所以 stop_execution_date 永远为 NULL。所以这对我来说不是解决方案。
      【解决方案6】:

      我想指出,此页面上的所有 T-SQL 都不会精确工作,因为它们都不会加入 syssessions 表以仅获取当前会话,因此可能包含误报.

      请参阅此内容:What does it mean to have jobs with a null stop date?

      您还可以通过分析 msdb 中的 sp_help_jobactivity 过程来验证这一点。

      我意识到这是关于 SO 的旧消息,但由于问题,我发现此消息仅部分有用。

      SELECT
          job.name, 
          job.job_id, 
          job.originating_server, 
          activity.run_requested_date, 
          DATEDIFF( SECOND, activity.run_requested_date, GETDATE() ) as Elapsed
      FROM 
          msdb.dbo.sysjobs_view job
      JOIN
          msdb.dbo.sysjobactivity activity
      ON 
          job.job_id = activity.job_id
      JOIN
          msdb.dbo.syssessions sess
      ON
          sess.session_id = activity.session_id
      JOIN
      (
          SELECT
              MAX( agent_start_date ) AS max_agent_start_date
          FROM
              msdb.dbo.syssessions
      ) sess_max
      ON
          sess.agent_start_date = sess_max.max_agent_start_date
      WHERE 
          run_requested_date IS NOT NULL AND stop_execution_date IS NULL
      

      【讨论】:

      • 这应该是真正的答案。至少还有一个关于此问题的其他 StackOverflow 问题(此处:stackoverflow.com/questions/18445825/…),其中一位评论者发现,仅查找 stop_execution_date 为空的 sysjobactivity 记录将包括几周前具有 run_requested_date 的记录,这些记录显然尚未运行。我自己也发现了同样的事情,当我查看卡住记录的 session_ids 时,我发现它们是针对以前的会话的。上面运行@efesar 的查询排除了那些历史记录。
      • 我同意。这绝对应该是答案,因为它很简洁,可以准确地告诉您当前正在运行哪些作业以及运行了多长时间。
      • 这应该是+1的答案
      • 同意。我正在 SQLServer 2016 中使用几个月前运行的作业测试此解决方案,并且脚本检查执行状态时未考虑 ag​​ent_start_date,因此它始终响应“作业正在运行”。
      【解决方案7】:

      我发现最简单的方法是创建一个存储过程。输入“JobName”并点击 go。

      /*-----------------------------------------------------------------------------------------------------------
      
          Document Title: usp_getJobStatus
      
          Purpose:        Finds a Current Jobs Run Status     
          Input Example:  EXECUTE usp_getJobStatus 'MyJobName'
      
      -------------------------------------------------------------------------------------------------------------*/
      
          IF OBJECT_ID ( 'usp_getJobStatus','P' ) IS NOT NULL
          DROP PROCEDURE  usp_getJobStatus;
      
          GO
      
              CREATE PROCEDURE  usp_getJobStatus 
                                @JobName NVARCHAR (1000)
      
          AS
      
              IF OBJECT_ID('TempDB..#JobResults','U') IS NOT NULL DROP TABLE #JobResults
              CREATE TABLE #JobResults ( 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,
                                         Request_Source        INT NOT NULL, 
                                         Request_Source_id     SYSNAME 
                                         COLLATE Database_Default      NULL, 
                                         Running               INT NOT NULL,
                                         Current_Step          INT NOT NULL, 
                                         Current_Retry_Attempt INT NOT NULL, 
                                         Job_State             INT NOT NULL ) 
      
              INSERT  #JobResults 
              EXECUTE master.dbo.xp_sqlagent_enum_jobs 1, '';
      
              SELECT  job.name                                                AS [Job_Name], 
                    ( SELECT  MAX(CAST( STUFF(STUFF(CAST(jh.run_date AS VARCHAR),7,0,'-'),5,0,'-') + ' ' + 
                              STUFF(STUFF(REPLACE(STR(jh.run_time,6,0),' ','0'),5,0,':'),3,0,':') AS DATETIME))
                      FROM    msdb.dbo.sysjobs AS j 
                          INNER JOIN msdb.dbo.sysjobhistory AS jh 
                             ON jh.job_id = j.job_id AND jh.step_id = 0 
                      WHERE j.[name] LIKE '%' + @JobName + '%' 
                      GROUP BY j.[name] )                                     AS [Last_Completed_DateTime], 
                    ( SELECT  TOP 1 start_execution_date 
                      FROM    msdb.dbo.sysjobactivity
                      WHERE   job_id = r.job_id
                      ORDER BY start_execution_date DESC )                    AS [Job_Start_DateTime],
                  CASE 
                      WHEN r.running = 0 THEN
                          CASE 
                              WHEN jobInfo.lASt_run_outcome = 0 THEN 'Failed'
                              WHEN jobInfo.lASt_run_outcome = 1 THEN 'Success'
                              WHEN jobInfo.lASt_run_outcome = 3 THEN 'Canceled'
                              ELSE 'Unknown'
                          END
                              WHEN r.job_state = 0 THEN 'Success'
                              WHEN r.job_state = 4 THEN 'Success'
                              WHEN r.job_state = 5 THEN 'Success'
                              WHEN r.job_state = 1 THEN 'In Progress'
                              WHEN r.job_state = 2 THEN 'In Progress'
                              WHEN r.job_state = 3 THEN 'In Progress'
                              WHEN r.job_state = 7 THEN 'In Progress'
                           ELSE 'Unknown' END                                 AS [Run_Status_Description]
              FROM    #JobResults AS r 
                  LEFT OUTER JOIN msdb.dbo.sysjobservers AS jobInfo 
                     ON r.job_id = jobInfo.job_id 
                  INNER JOIN msdb.dbo.sysjobs AS job 
                     ON r.job_id = job.job_id 
              WHERE   job.[enabled] = 1
                      AND job.name LIKE '%' + @JobName + '%'
      

      【讨论】:

        【解决方案8】:

        上面的任务有效,但我在 msdb.dbo.sysjobactivity 中看到了很多记录 其中 run_Requested_date 不为空 并且 stop_execution_date 为空 ---- 并且该作业当前未运行。

        我建议运行以下脚本来清除所有虚假条目(确保当时没有正在运行的作业)。

        SQL2008:

            delete activity
            from msdb.dbo.sysjobs_view job  
            inner join msdb.dbo.sysjobactivity activity on job.job_id = activity.job_id 
            where  
                activity.run_Requested_date is not null  
            and activity.stop_execution_date is null  
        

        【讨论】:

          【解决方案9】:
          ;WITH CTE_JobStatus
          AS (
              SELECT DISTINCT NAME AS [JobName]
                  ,s.step_id
                  ,s.step_name
                  ,CASE 
                      WHEN [Enabled] = 1
                          THEN 'Enabled'
                      ELSE 'Disabled'
                      END [JobStatus]
                  ,CASE 
                      WHEN SJH.run_status = 0
                          THEN 'Failed'
                      WHEN SJH.run_status = 1
                          THEN 'Succeeded'
                      WHEN SJH.run_status = 2
                          THEN 'Retry'
                      WHEN SJH.run_status = 3
                          THEN 'Cancelled'
                      WHEN SJH.run_status = 4
                          THEN 'In Progress'
                      ELSE 'Unknown'
                      END [JobOutcome]
                  ,CONVERT(VARCHAR(8), sjh.run_date) [RunDate]
                  ,CONVERT(VARCHAR(8), STUFF(STUFF(CONVERT(TIMESTAMP, RIGHT('000000' + CONVERT(VARCHAR(6), sjh.run_time), 6)), 3, 0, ':'), 6, 0, ':')) RunTime
                  ,RANK() OVER (
                      PARTITION BY s.step_name ORDER BY sjh.run_date DESC
                          ,sjh.run_time DESC
                      ) AS rn
                  ,SJH.run_status
              FROM msdb..SYSJobs sj
              INNER JOIN msdb..SYSJobHistory sjh ON sj.job_id = sjh.job_id
              INNER JOIN msdb.dbo.sysjobsteps s ON sjh.job_id = s.job_id
                  AND sjh.step_id = s.step_id
              WHERE (sj.NAME LIKE 'JOB NAME')
                  AND sjh.run_date = CONVERT(CHAR, getdate(), 112)
              )
          SELECT *
          FROM CTE_JobStatus
          WHERE rn = 1
              AND run_status NOT IN (1,4)
          

          【讨论】:

            【解决方案10】:

            我在查询 MSDB 表(也就是上面列出的代码)的一台服务器上遇到了问题,因为我的一项工作会开始运行,但事实并非如此。有一个系统存储过程会返回执行状态,但是不能执行插入 exec 语句而不会出错。里面是另一个系统存储过程,可以与 insert exec 语句一起使用。

            INSERT INTO #Job
            EXEC master.dbo.xp_sqlagent_enum_jobs 1,dbo
            

            以及将其加载到的表:

            CREATE TABLE #Job 
                           (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) 
            

            【讨论】:

              【解决方案11】:
              SELECT sj.name
                FROM msdb..sysjobactivity aj
                JOIN msdb..sysjobs sj
                  on sj.job_id = aj.job_id
               WHERE aj.stop_execution_date  IS NULL     -- job hasn't stopped running
                 AND aj.start_execution_date IS NOT NULL -- job is currently running
                 AND sj.name = '<your Job Name>'
                 AND NOT EXISTS( -- make sure this is the most recent run
                                 select 1
                                   from msdb..sysjobactivity new
                                  where new.job_id = aj.job_id
                                    and new.start_execution_date > aj.start_execution_date ) )
              print 'running'
              

              【讨论】:

              • 欢迎来到本站。请看一下这个:stackoverflow.com/help/how-to-answer 并为您的代码提供一些解释
              • 除了这个代码完全符合用户的要求之外,还需要什么额外的解释......
              【解决方案12】:

              这将显示上次运行状态/时间,或者如果正在运行,它会显示当前运行时间、步骤编号/信息和 SPID(如果它具有关联的 SPID)。它还显示了启用/禁用和作业用户,其中它为未解析的用户帐户转换为 NT SID 格式。

              CREATE TABLE #list_running_SQL_jobs
              (
                  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
                , request_source INT NOT NULL
                , request_source_id sysname NULL
                , running INT NOT NULL
                , current_step INT NOT NULL
                , current_retry_attempt INT NOT NULL
                , job_state INT NOT NULL
              );
              
              DECLARE @sqluser NVARCHAR(128)
                    , @is_sysadmin INT;
              
              SELECT @is_sysadmin = ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0);
              
              DECLARE read_sysjobs_for_running CURSOR FOR
                  SELECT DISTINCT SUSER_SNAME(owner_sid)FROM msdb.dbo.sysjobs;
              OPEN read_sysjobs_for_running;
              FETCH NEXT FROM read_sysjobs_for_running
              INTO @sqluser;
              
              WHILE @@FETCH_STATUS = 0
              BEGIN
                  INSERT INTO #list_running_SQL_jobs
                  EXECUTE master.dbo.xp_sqlagent_enum_jobs @is_sysadmin, @sqluser;
                  FETCH NEXT FROM read_sysjobs_for_running
                  INTO @sqluser;
              END;
              
              CLOSE read_sysjobs_for_running;
              DEALLOCATE read_sysjobs_for_running;
              
              SELECT j.name
                   , 'Enbld' = CASE j.enabled
                                   WHEN 0
                                       THEN 'no'
                                   ELSE 'YES'
                               END
                   , '#Min' = DATEDIFF(MINUTE, a.start_execution_date, ISNULL(a.stop_execution_date, GETDATE()))
                   , 'Status' = CASE
                                    WHEN a.start_execution_date IS NOT NULL
                                        AND a.stop_execution_date IS NULL
                                        THEN 'Executing'
                                    WHEN h.run_status = 0
                                        THEN 'FAILED'
                                    WHEN h.run_status = 2
                                        THEN 'Retry'
                                    WHEN h.run_status = 3
                                        THEN 'Canceled'
                                    WHEN h.run_status = 4
                                        THEN 'InProg'
                                    WHEN h.run_status = 1
                                        THEN 'Success'
                                    ELSE 'Idle'
                                END
                   , r.current_step
                   , spid = p.session_id
                   , owner = ISNULL(SUSER_SNAME(j.owner_sid), 'S-' + CONVERT(NVARCHAR(12), CONVERT(BIGINT, UNICODE(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 1))) - CONVERT(BIGINT, 256) * CONVERT(BIGINT, UNICODE(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 1)) / 256)) + '-' + CONVERT(NVARCHAR(12), UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 4), 1)) / 256 + CONVERT(BIGINT, NULLIF(UNICODE(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 1)) / 256, 0)) - CONVERT(BIGINT, UNICODE(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 1)) / 256)) + ISNULL('-' + CONVERT(NVARCHAR(12), CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 5), 1))) + CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 6), 1))) * CONVERT(BIGINT, 65536) + CONVERT(BIGINT, NULLIF(SIGN(LEN(CONVERT(NVARCHAR(256), j.owner_sid)) - 6), -1)) * 0), '') + ISNULL('-' + CONVERT(NVARCHAR(12), CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 7), 1))) + CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 8), 1))) * CONVERT(BIGINT, 65536) + CONVERT(BIGINT, NULLIF(SIGN(LEN(CONVERT(NVARCHAR(256), j.owner_sid)) - 8), -1)) * 0), '') + ISNULL('-' + CONVERT(NVARCHAR(12), CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 9), 1))) + CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 10), 1))) * CONVERT(BIGINT, 65536) + CONVERT(BIGINT, NULLIF(SIGN(LEN(CONVERT(NVARCHAR(256), j.owner_sid)) - 10), -1)) * 0), '') + ISNULL('-' + CONVERT(NVARCHAR(12), CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 11), 1))) + CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 12), 1))) * CONVERT(BIGINT, 65536) + CONVERT(BIGINT, NULLIF(SIGN(LEN(CONVERT(NVARCHAR(256), j.owner_sid)) - 12), -1)) * 0), '') + ISNULL('-' + CONVERT(NVARCHAR(12), CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 13), 1))) + CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 14), 1))) * CONVERT(BIGINT, 65536) + CONVERT(BIGINT, NULLIF(SIGN(LEN(CONVERT(NVARCHAR(256), j.owner_sid)) - 14), -1)) * 0), '')) --SHOW as NT SID when unresolved
                   , a.start_execution_date
                   , a.stop_execution_date
                   , t.subsystem
                   , t.step_name
              FROM msdb.dbo.sysjobs j
                  LEFT OUTER JOIN (SELECT DISTINCT * FROM #list_running_SQL_jobs) r
                      ON j.job_id = r.job_id
                  LEFT OUTER JOIN msdb.dbo.sysjobactivity a
                      ON j.job_id = a.job_id
                          AND a.start_execution_date IS NOT NULL
                          --AND a.stop_execution_date IS NULL
                          AND NOT EXISTS
                          (
                              SELECT *
                              FROM msdb.dbo.sysjobactivity at
                              WHERE at.job_id = a.job_id
                                  AND at.start_execution_date > a.start_execution_date
                          )
                  LEFT OUTER JOIN sys.dm_exec_sessions p
                      ON p.program_name LIKE 'SQLAgent%0x%'
                          AND j.job_id = SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 7, 2) + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 5, 2) + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 3, 2) + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 1, 2) + '-' + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 11, 2) + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 9, 2) + '-' + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 15, 2) + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 13, 2) + '-' + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 17, 4) + '-' + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 21, 12)
                  LEFT OUTER JOIN msdb.dbo.sysjobhistory h
                      ON j.job_id = h.job_id
                          AND h.instance_id = a.job_history_id
                  LEFT OUTER JOIN msdb.dbo.sysjobsteps t
                      ON t.job_id = j.job_id
                          AND t.step_id = r.current_step
              ORDER BY 1;
              
              DROP TABLE #list_running_SQL_jobs;
              

              【讨论】:

              • 这段代码大约是我正在寻找的代码的 99%。认为有一种方法可以添加另一列来显示当前正在执行的作业的最后运行持续时间?我尝试绑定 sysjobhistory.run_duration 字段,但如果当前状态为“正在执行”,则不会撤回值。感谢您让我走到这一步。
              【解决方案13】:

              这是一个老问题,但我刚刚遇到了类似的情况,我需要检查 SQL Server 上的作业状态。很多人提到 sysjobactivity 表并指出 MSDN 文档很棒。不过,我还想强调一下Job Activity Monitor,它提供了在您的服务器上定义的所有作业的状态。

              【讨论】:

                【解决方案14】:

                以下脚本获取服务器上每个作业的作业状态。它还告诉您有多少步以及当前正在运行的步和经过的时间。

                SELECT sj.Name,
                    CASE
                        WHEN sja.start_execution_date IS NULL THEN 'Never ran'
                        WHEN sja.start_execution_date IS NOT NULL AND sja.stop_execution_date IS NULL THEN 'Running'
                        WHEN sja.start_execution_date IS NOT NULL AND sja.stop_execution_date IS NOT NULL THEN 'Not running'
                    END AS 'RunStatus',
                    CASE WHEN sja.start_execution_date IS NOT NULL AND sja.stop_execution_date IS NULL then js.StepCount else null end As TotalNumberOfSteps,
                    CASE WHEN sja.start_execution_date IS NOT NULL AND sja.stop_execution_date IS NULL then ISNULL(sja.last_executed_step_id+1,js.StepCount) else null end as currentlyExecutingStep,
                    CASE WHEN sja.start_execution_date IS NOT NULL AND sja.stop_execution_date IS NULL then datediff(minute, sja.run_requested_date, getdate()) ELSE NULL end as ElapsedTime
                FROM msdb.dbo.sysjobs sj
                JOIN msdb.dbo.sysjobactivity sja
                ON sj.job_id = sja.job_id
                CROSS APPLY (SELECT COUNT(*) FROM msdb.dbo.sysjobsteps as js WHERE js.job_id = sj.job_id) as js(StepCount)
                WHERE session_id = (
                    SELECT MAX(session_id) FROM msdb.dbo.sysjobactivity)
                ORDER BY RunStatus desc
                

                【讨论】:

                  【解决方案15】:

                  我使用评分最高的答案创建了一个简单的 SQL 函数来检查 SQL 代理作业是否已经在运行:

                  -- ===================================================================================
                  -- Function: "IsJobAlreadyRunning"  |  Author: Geoff Griswald  |  Created: 2021-05-06
                  -- Description: Check if a SQL Agent Job is already Running - Return 1 if Yes, 0 if No
                  -- ===================================================================================
                  CREATE FUNCTION dbo.IsJobAlreadyRunning (@AgentJobName varchar(140))
                  RETURNS bit
                  AS
                  BEGIN
                  DECLARE @Result bit = 0
                       IF EXISTS (SELECT job.name
                                    FROM msdb.dbo.sysjobs_view job
                              INNER JOIN msdb.dbo.sysjobactivity activity ON job.job_id = activity.job_id
                              INNER JOIN msdb.dbo.syssessions sess ON sess.session_id = activity.session_id
                              INNER JOIN (SELECT MAX(agent_start_date) AS max_agent_start_date
                                            FROM msdb.dbo.syssessions) sess_max ON sess.agent_start_date = sess_max.max_agent_start_date
                                   WHERE run_requested_date IS NOT NULL 
                                     AND stop_execution_date IS NULL
                                     AND job.name = @AgentJobName)
                     SET @Result = 1
                  RETURN @Result
                  END;
                  

                  这很有用,因为我可以调用此函数并在我尝试启动它之前检查我要启动的作业是否已经在运行,而不会给我的代码添加大量臃肿。例如:

                  DECLARE @JobName varchar(140) = 'MyAgentJobName'
                       IF (SELECT dbo.IsJobAlreadyRunning(@JobName)) = 0
                     EXEC msdb.dbo.sp_start_job @JobName
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-05-02
                    • 2017-06-08
                    • 2021-09-30
                    • 2019-07-01
                    相关资源
                    最近更新 更多