SQL Server 代理作业失败并返回错误 258

本文提供有关导致MICROSOFT SQL Server 代理作业失败并生成错误代码 258 的问题的故障排除指南。

症状

SQL Server 代理服务运行,但计划的 SQL Server 代理作业不会运行。 除了登录失败之外,SQL Server 和代理日志还会显示网络和身份验证超时。

以下示例显示了添加到日志中的错误消息:

SQLServer Error: 258, TCP Provider: Timeout error [258]
ODBC Error: 0, Login timeout expired [SQLSTATE HYT00]
SQLServer Error: 258, Unable to complete login process due to delay in prelogin response [SQLSTATE 08001]
Logon to server '<ServerName>' failed (ConnLogJobHistory)

原因

此问题可能由以下任何根本问题引起:

  • 阻止 SQL 代理使用的 msdb 系统表。 此阻止可防止作业元数据的读取和写入操作。
    • 示例系统表包括dbo.sysjobsdbo.sysjobschedulersdbo.jobsteps
  • 重要的 SQL Server Agent 线程或其他进程级问题中的无响应(挂起)。
  • SQL Server 中的工作线程耗尽(没有可用的线程)。 这种耗尽会导致代理程序无法连接或处理时间表。

解决方案

  1. 验证 SQL Server 代理服务是否正在运行。 使用以下 PowerShell 命令之一:

    • 对于默认 SQL 实例:

      Get-Service -Name "SQLSERVERAGENT"
      
    • 对于命名的 SQL 实例:

      Get-Service -Name "SQLSERVERAGENT$<InstanceName>"
      
  2. 如果 SQL Server 代理服务未运行,请使用以下命令之一启动它:

    • 对于默认 SQL 实例:

      Start-Service -Name "SQLSERVERAGENT"
      
    • 对于命名的 SQL 实例:

      Start-Service -Name "SQLSERVERAGENT$<InstanceName>"
      
  3. 如果在启动 SQL Server 代理服务后作业继续失败,请转到下一步。 如果作业成功完成,问题就得到解决,无需执行进一步的操作。

  4. 检查msdb中的作业和计划。 启动 SQL Server Management Studio (SSMS),并运行以下查询:

    USE msdb;
    GO
    -- List enabled jobs
    SELECT name, enabled, description 
    FROM msdb.dbo.sysjobs 
    WHERE enabled = 1;
    GO
    -- List schedules and next run information
    SELECT 
        s.name AS ScheduleName,
        j.name AS JobName,
        s.enabled AS ScheduleEnabled,
        s.active_start_date,
        s.active_end_time
    FROM msdb.dbo.sysjobs j
    JOIN msdb.dbo.sysjobschedules js ON j.job_id = js.job_id
    JOIN msdb.dbo.sysschedules s ON js.schedule_id = s.schedule_id
    WHERE j.enabled = 1;
    GO
    

    分析已启用但失败的任何作业的查询输出。 调查任何有问题的作业的作业历史记录和作业步骤输出,以识别和修复基础问题。

  5. 通过在 SSMS 中运行以下查询来检测代理系统表msdb上的阻塞会话:

    USE msdb;
    GO
    SELECT 
        session_id, 
        blocking_session_id, 
        wait_type, 
        wait_duration_ms, 
        resource_description
    FROM sys.dm_os_waiting_tasks
    WHERE resource_description LIKE '%sysjobs%'
       OR resource_description LIKE '%sysjobschedulers%'
       OR resource_description LIKE '%jobsteps%';
    GO 
    
    • 若要标识与阻止会话关联的查询,请在 SSMS 中运行以下查询:

      SELECT 
          wt.session_id,
          wt.blocking_session_id,
          wt.wait_type,
          wt.wait_duration_ms,
          wt.resource_description,
          er.status,
          er.command,
          er.cpu_time,
          er.total_elapsed_time,
          txt.text AS sql_text
      FROM sys.dm_os_waiting_tasks wt
      LEFT JOIN sys.dm_exec_requests er 
             ON wt.session_id = er.session_id
      CROSS APPLY sys.dm_exec_sql_text(er.sql_handle) AS txt
      WHERE wt.resource_description LIKE '%sysjobs%'
         OR wt.resource_description LIKE '%sysjobschedulers%'
         OR wt.resource_description LIKE '%jobsteps%';
      
  6. 解决或终止在上一步中标识的任何阻塞会话。 若要终止会话,请在 SSMS 中运行以下查询:

    Kill <Blocking_Session_ID>
    

    解决或终止所有阻塞会话后,请转到下一步。

  7. 在 SSMS 中运行以下查询,以检查是否存在任何工作线程、线程或资源运行状况问题:

    /* ============================================================
       HEALTH CHECK (Worker, CPU, Memory)
       ============================================================ */
    
    SELECT 
        Section,
        Metric,
        Value,
        ExtraInfo
    FROM (
    
        /* ===============================
           WORKER THREAD STATUS
           =============================== */
        SELECT 
            CAST('WORKER THREAD STATUS' AS VARCHAR(MAX)) AS Section,
            CAST(CONCAT('Scheduler ', scheduler_id) AS VARCHAR(MAX)) AS Metric,
            CAST(CONCAT('Workers: ', active_workers_count, '/', current_workers_count) AS VARCHAR(MAX)) AS Value,
            CAST(CONCAT('WorkQueue=', work_queue_count, ', Idle=', is_idle) AS VARCHAR(MAX)) AS ExtraInfo
        FROM sys.dm_os_schedulers
        WHERE scheduler_id < 255
    
        UNION ALL
    
        /* ===============================
           CPU PRESSURE
           =============================== */
        SELECT
            CAST('CPU PRESSURE' AS VARCHAR(MAX)) AS Section,
            CAST(CONCAT('Scheduler ', scheduler_id) AS VARCHAR(MAX)) AS Metric,
            CAST(CONCAT('RunnableTasks=', runnable_tasks_count) AS VARCHAR(MAX)) AS Value,
            CAST(CONCAT('PendingIO=', pending_disk_io_count) AS VARCHAR(MAX)) AS ExtraInfo
        FROM sys.dm_os_schedulers
        WHERE scheduler_id < 255
    
        UNION ALL
    
        /* ===============================
           MEMORY STATUS (System)
           =============================== */
        SELECT
            CAST('MEMORY STATUS' AS VARCHAR(MAX)) AS Section,
            CAST('SystemMemoryState' AS VARCHAR(MAX)) AS Metric,
            CAST(system_memory_state_desc AS VARCHAR(MAX)) AS Value,
            CAST(CONCAT('TotalMB=', total_physical_memory_kb/1024, 
                        ', AvailableMB=', available_physical_memory_kb/1024) AS VARCHAR(MAX)) AS ExtraInfo
        FROM sys.dm_os_sys_memory
    
        UNION ALL
    
        /* ===============================
           PAGE LIFE EXPECTANCY
           =============================== */
        SELECT
            CAST('PAGE LIFE EXPECTANCY' AS VARCHAR(MAX)) AS Section,
            CAST('PLE' AS VARCHAR(MAX)) AS Metric,
            CAST(cntr_value AS VARCHAR(MAX)) AS Value,
            CAST(NULL AS VARCHAR(MAX)) AS ExtraInfo
        FROM sys.dm_os_performance_counters
        WHERE counter_name = 'Page life expectancy'
          AND object_name LIKE '%Buffer Manager%'
    
    ) AS x
    ORDER BY Section, Metric;
    

    根据所给症状,确定运行状况检查查询的输出是否存在以下任何问题:

    • 工作线程压力:
      • 例如 Workers: 512/512,工人疲惫。
      • WorkQueue 大于零。 此值指示任务正在等待,并且系统已重载。
    • CPU 压力:
      • RunnableTasks 大于零。 此值指示存在 CPU 瓶颈。 非零值还可以指示 SQL Server 计划程序被线程(非生成计划程序)垄断。
    • 内存压力:
      • Memory stateLOW。 此值指示整个系统内存不足。
      • 一个低值 AvailableMB。 此值表示 SQL Server 的内存使用率较高。
      • PLE 的值小于 300。 此值表示内存变动率较高。
  8. 如果在上一步中发现了任何工作进程、CPU 或内存问题,请减少当前工作负荷以解决这些问题。 如果未确定任何问题,请转到下一步。

  9. 通过运行以下 PowerShell 命令之一来重启 SQL Server 代理:

    重要

    重启 SQL Server 代理会中断任何当前正在运行的作业。

    • 对于默认 SQL Server 实例:

      Restart-Service -Name "SQLSERVERAGENT"
      
    • 对于命名的 SQL Server 实例:

      Restart-Service -Name "SQLAgent$<InstanceName>"
      
  10. SQL Server 代理重启后,请验证作业现在是否正在运行。 使用 作业活动监视器