识别辅助副本上缺少的代理作业

Identify agent jobs missing on secondary replicas

我正在尝试设置一个进程来检查可用性组中所有服务器上的代理作业,并报告辅助副本中可能丢失的任何作业。

我在 AG 的所有服务器上设置了 CMS,并且可以 运行 跨副本查询代理作业,但我只想 return 一些服务器上的作业,但不是全部他们中的。

我编写了一个查询以使用 COUNT() 获取此信息,但由于查询结果按服务器分组,因此无法正常工作。我还尝试将结果放在临时 table 中以查看是否有帮助,但这似乎并没有太大的不同。

AG 中有四台服务器,以下查询应该 return 不在所有四台服务器上的任何作业的名称,但因为它似乎 return 服务器名称它没有将它们识别为同一个工作。

CREATE TABLE #jobs (
    JobName NVARCHAR(128))

INSERT INTO #jobs
SELECT name JobName
FROM sysjobs 

SELECT * 
FROM #jobs
GROUP BY JobName
HAVING COUNT(*) < 4
ORDER BY JobName

DROP TABLE #jobs

当前的查询将抛出如下结果集:

+------------+------------------------------------------+
| ServerName |                 JobName                  |
+------------+------------------------------------------+
| ServerA    | DBA DatabaseBackup - AG_DATABASES - FULL |
| ServerA    | OutputFile Cleanup                       |
| ServerB    | DBA DatabaseBackup - AG_DATABASES - FULL |
| ServerB    | IndexOptimize - USER_DATABASES           |
| ServerC    | DBA DatabaseBackup - AG_DATABASES - FULL |
| ServerB    | IndexOptimize - USER_DATABASES           |
| ServerD    | DBA DatabaseBackup - AG_DATABASES - FULL |
| ServerD    | Output File Cleanup                      |
+------------+------------------------------------------+

作业 DBA DatabaseBackup - AG_DATABASES - 所有四台服务器都存在 FULL 所以我不想要这个 returned,但是因为来自 CMS 连接的隐式服务器名列它不会将它们识别为相同的值。

所以想要一个 returns 少于 4 个条目的所有 JobName 的查询。创建临时 table 没有意义,直接查询 sysjobs table,如:

SELECT name  
FROM sysjobs
GROUP BY name
HAVING COUNT(*) < 4
ORDER BY name

如果您的 CMS 始终插入服务器名称,后跟作业名称,作业名称用破折号分隔,中间用空格包围...您可以使用如下内容解析服务器名称:

INSERT INTO #jobs
SELECT REPLACE(SUBSTRING(name, CHARINDEX(' - ', name),LEN(name)) , ' - ', '') JobName
FROM sysjobs 

如 GMB 所述,您需要提取部分 "name" 字段。

我建议将字符串拆分为 ServerName 和 JobName。

假设名称由 - 分隔,就像在您的示例中一样,您的代码可能如下所示。

CREATE TABLE #jobs (
ServerName NVARCHAR(128)    
,JobName NVARCHAR(128))

INSERT INTO #jobs
SELECT 
LEFT(name,CHARINDEX('-',name)-1) AS ServerName --Takes the Part left of the first -
, RIGHT(name,LEN(name) - CHARINDEX('-',name)) AS JobName --Takes the Part right of the first -
FROM sysjobs 

SELECT JobName 
FROM #jobs
GROUP BY JobName
HAVING COUNT(*) < 4
ORDER BY JobName

DROP TABLE #jobs

您可以使用 STUFF() 函数将所有服务器名称放在一列中,只计算作业名称。

SELECT JobName, STUFF((
    SELECT ',' + CAST([ServerName] AS VARCHAR(MAX)) 
    FROM sysjobs 
    WHERE results.JobNames = sysjobs.JobNames
    FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
  ,1,1,'') AS ServerNames 
FROM #jobs results
GROUP BY JobName
HAVING COUNT(*) < 4
ORDER BY JobName

我已经设法以另一种方式绕过它。我现在已经在我的 CMS 服务器上设置了一个 table,并且我有一个存储过程,它将使用来自 AG 中所有服务器的代理作业的详细信息填充 table。 然后我可以从那里 运行 以下查询,它就像一个魅力:

SELECT ServerName
       ,JobName
FROM AgentJobs
WHERE JobName IN(
                    SELECT JobName
                    FROM AgentJobs
                    WHERE JobCategory = 'Production'
                    GROUP BY JobName
                    HAVING COUNT(*) < 4)