SSIS 竞争条件
SSIS Race Condition
我们利用 SSIS (SQL/BIDS 2008) 每天生成近 1000 份报告。同一个包在 SQL Agent 中按错开的时间表安排了 5 次。
- Job1 - 每 5 分钟从 12:00
- Job2 - 从 12:01
每 5 分钟
- Job3 - 每 5 分钟从 12:02
- Job4 - 每 5 分钟从 12:03
- Job5 - 从 12:04
每 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 使用的值。
我们利用 SSIS (SQL/BIDS 2008) 每天生成近 1000 份报告。同一个包在 SQL Agent 中按错开的时间表安排了 5 次。
- Job1 - 每 5 分钟从 12:00
- Job2 - 从 12:01 每 5 分钟
- Job3 - 每 5 分钟从 12:02
- Job4 - 每 5 分钟从 12:03
- Job5 - 从 12:04 每 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 使用的值。