如何在T-SQL中运行多个实例时只执行一部分代码

时间:2016-06-01 19:47:39

标签: sql sql-server tsql sql-server-2012

我有一个从业务代码调用的存储过程。此代码使用并行性,因此根据某些条件,此SP的多个实例可以同时运行。

此SP中有一些逻辑我只想执行一次。我有一个表(我们称之为HISTORY),它包含运行的UID和执行此部分代码时的DATETIME。这是我的流程:

SP BEGIN
  -- some logic
  IF certain conditions are met, check if HISTORY does not have an entry for the UID
    1. Add an entry in HISTORY for the current UID
    2. Run the once only code
SP END

问题在于,如果不同的实例同时到达该部分,有时上述逻辑仍会被执行多次。我该怎么做才能确保它只运行一次?

谢谢!

1 个答案:

答案 0 :(得分:1)

BEGIN TRANSACTION;
    INSERT [HISTORY](UID, ...)
    SELECT @UID, ...
    WHERE NOT EXISTS (
        SELECT * FROM [HISTORY] WITH (HOLDLOCK) WHERE UID = @UID
    );

    IF @@ROWCOUNT = 1 BEGIN;
      -- we inserted, do logic that should run only once
    END;
COMMIT;

HOLDLOCK(相当于在SERIALIZABLE下运行事务,但更精细)确保并行运行的其他事务不能在HISTORY中为该UID插入条目;尝试这样的任何事务都将阻塞,直到第一个INSERT完成然后返回(因为一行已经存在)。确保UID上的索引存在,否则会锁定比性能健康更多的索引。

正确获取这样的代码总是很棘手,因此请务必在实践中对同一(和不同)UID的并发插入进行压力测试。