从具有重试详细信息(id和重试计数)的表中检索失败的作业

Dai*_*Dai 6 sql sql-server

我为一个非直观的主题标题道歉.

我有一个表,Jobs其中每一行代表一个由计算机程序执行的维护任务.它有这样的设计:

CREATE TABLE Jobs (
    JobId bigint PRIMARY KEY,
    ...
    Status int NOT NULL,
    OriginalJobId bigint NULL
)
Run Code Online (Sandbox Code Playgroud)

创建/启动作业时,其行将添加到表中,其状态为0.作业完成后,其状态将更新为1,当作业失败时,其状态将更新为2.当作业失败时,作业管理器将通过复制失败作业的详细信息将新行插入Jobs表中来重试作业,并重置Statusto 0并使用原始(失败)JobId OriginalJobId进行跟踪.如果再尝试失败,则应该再次尝试多达3次,以后每次重试将保持原来JobIdOriginalJobId列.

我的问题是尝试制定一个查询来获取当前失败的作业集并获得重试次数.

这是表格中的示例数据:

JobId | Status | OriginalJobId
    1,       1,           NULL    -- Successful initial job
    2,       0,           NULL    -- Pending initial job
    3,       2,           NULL    -- Failed initial job
    4,       1,              3    -- Successful retry of Job 3
    5,       2,           NULL    -- Failed initial job
    6,       2,              5    -- Failed retry 1 of Job 5
    7,       2,              5    -- Failed retry 2 of Job 5 -- should be tried again for 1 more time
    8,       2,           NULL    -- Failed initial job
    9,       2,              8    -- Failed retry 1 of Job 8
   10,       2,              8    -- Failed retry 2 of Job 8
   11,       2,              8    -- Failed retry 3 of Job 8 -- don't try again
   12,       2,           NULL    -- Failed initial job
Run Code Online (Sandbox Code Playgroud)

我的查询需要返回:

 JobId | RetryCount
     5,           2
    12,           0
Run Code Online (Sandbox Code Playgroud)

注意如何3不包括Job,因为它的上次重试成功(状态1).类似地,Job 8被排除,因为重试次数超过了3的限制.5包括Job ,因为它仍然失败并且只有2次重试,并且12包含Job 并且还没有重试.

我在想解决方案是这样的:

SELECT
    J1.JobId
FROM
    Jobs AS J1
    LEFT OUTER JOIN Jobs AS J2 ON J1.JobId = J2.OriginalJobId
WHERE
    J1.Status = 2
Run Code Online (Sandbox Code Playgroud)

...但我想不出如何获取RetryCount数据.

这是我为这个问题创建的SQLFiddle,其中一个解决方案如下:

http://sqlfiddle.com/#!6/8765f

更新

这是一个更新的SQLFiddle,它比较了目前为止提供的5个解决方案(我添加了一个额外的HAVING子句来删除重试次数超过3次的作业)

http://sqlfiddle.com/#!6/8765f/23

性能方面,我认为GarethD的答案是最好的,因为它具有最简单的执行计划,并且倾向于以最快的时间在SqlFiddle中完成.

我的生产表有大约14,000,000行,所以显然结果会有所不同.我会在生产中尝试每一个,看看哪个是最快的,然后相应地选择答案.

谢谢大家的帮助!

Gar*_*thD 5

以下返回所需的结果:

SELECT  J1.JobId,
        Retries = COUNT(J2.JobId)
FROM    Jobs AS J1
        INNER JOIN Jobs AS J2 
            ON J1.JobId = J2.OriginalJobId
WHERE   J1.Status = 2
GROUP BY J1.JobId
HAVING COUNT(CASE WHEN J2.Status = 1 THEN 1 END) = 0;
Run Code Online (Sandbox Code Playgroud)

我已将其更改为INNER连接,以便仅包括已重试的作业,但这可以切换回LEFT连接以包括尚未重试的失败作业.我还添加了一个HAVING子句来排除任何在重试时没有失败的作业.


编辑

如上所述,使用INNER JOIN意味着您只返回已重试的作业,以获取您需要使用的所有失败作业LEFT JOIN,这将意味着重试作为失败的作业返回,因此我添加了一个额外的谓词J1.OriginalJobId IS NULL以确保只有原始工作被退回:

SELECT  J1.JobId,
        Retries = COUNT(J2.JobId)
FROM    Jobs AS J1
        LEFT JOIN Jobs AS J2 
            ON J1.JobId = J2.OriginalJobId
WHERE   J1.Status = 2
AND     J1.OriginalJobId IS NULL
GROUP BY J1.JobId
HAVING COUNT(CASE WHEN J2.Status = 1 THEN 1 END) = 0;
Run Code Online (Sandbox Code Playgroud)

关于SQL小提琴的例子