SSIS 竞争条件

SSIS Race Condition

我们利用 SSIS (SQL/BIDS 2008) 每天生成近 1000 份报告。同一个包在 SQL Agent 中按错开的时间表安排了 5 次。

SSIS 查询 Report table,如果报告在给定日期还没有 运行(检查 ReportLog)并且该报告不是运行当前(检查WorkQueue)第一个(顶部)报告被拾取,并且运行。

该查询有效:

SELECT TOP 1 R.ReportID
FROM Report R
LEFT JOIN ReportLog L ON R.ReportID=L.ReportID AND L.RunDate >= CONVERT(DATE,GETDATE())
LEFT JOIN WorkQueue Q ON R.ReportID=Q.ReportID
WHERE R.Active=1
AND L.ReportID IS NULL 
AND Q.ReportID IS NULL

SSIS 包在 selecting 这个 TOP 1 ReportID(存储在 SSIS 变量中)后,将 ReportID 插入 WorkQueue,因此没有其他实例包将尝试使用那个 ReportID。插入发生在 select.

之后的下一步

大多数时候,大多数日子,这都能正常工作。然而,每隔一段时间,两个 SSIS 包就会 运行ning 在(几毫秒内)完全相同的时间结束,并且两个 return 相同 TOP 1 ReportID 导致彼此出现问题,因为它们都是执行相同的过程,并操作相同的基础数据。

现在,我们正在考虑实施一个父 SSIS 包,它执行 select 并将 ReportID 与作业一起放入 "buffer" table #要提取的 5 个子包之一(而不是子包都自己做 select top 1),但这看起来很老套。

我们考虑的另一个选项是 WorkQueue table 上的 instead of insert 触发器,这会在重复插入时引发错误。

我想知道在 SSIS 中是否有任何其他方法可以在不进行太多重新设计的情况下防止这种情况。

如何避免触发器并使用 OUTPUT 子句?

INSERT INTO
    WorkQueue
OUTPUT Inserted.ReportID
SELECT TOP 1 R.ReportID
FROM Report R
    LEFT JOIN ReportLog L ON R.ReportID=L.ReportID AND L.RunDate >= CONVERT(DATE,GETDATE())
    LEFT JOIN WorkQueue Q ON R.ReportID=Q.ReportID
WHERE R.Active=1
    AND L.ReportID IS NULL 
    AND Q.ReportID IS NULL;

这应该允许您将 row 行弹出到 workQueue table 以声明它用于当前进程并同时检索 SSIS 使用的值。