【问题标题】:What is the correct way to capture OUTPUT deleted.x from EXEC stored_procedure?从 EXEC 存储过程中捕获 OUTPUT deleted.x 的正确方法是什么?
【发布时间】:2017-05-29 21:10:24
【问题描述】:

我在高并发条件下将表用作FIFO queue,并像这样以原子方式出列:

CREATE PROCEDURE [jobs].[DequeueJob]        
AS
BEGIN
    DELETE TOP(1) 
    FROM jobs.JobQueue WITH (ROWLOCK, READPAST) 
    OUTPUT deleted.JobID;
END

我从另一个调用这个存储过程来捕获和使用deleted.JobID,所以我有这个:

CREATE PROCEDURE [jobs].[GetJob]        
AS
BEGIN
    DECLARE @Job TABLE (JobID int)       

    INSERT @Job EXEC jobs.DequeueJob    

    DECLARE @JobID int
    SET @JobID = (SELECT JobID from @Job)   

    UPDATE jobs.Jobs 
    SET IsInQueue = 0 
    WHERE JobID = @JobID

    SELECT * 
    FROM jobs.Jobs 
    WHERE JobID = @JobID
END

这很好用,但有异味:要获得我想要使用的值 (JobID),我必须创建一个包含一列的表变量,INSERT 一行,然后立即@987654328 @同一行退出。当我调用EXEC jobs.DequeueJob 时,是否有更好的方法(从可读性或优化角度)捕获deleted.JobID 不会破坏其原子性?

EXEC @JobID = jobs.DequeueJob 是有效的语法,看起来很有希望,但它捕获了返回值,而不是 OUTPUT 值。 This answer 对几个结果传递选项进行了很好的讨论,但我找不到适合我的情况的方法。

我使用的是 SQL Server 2012 SP3,但如果更新的版本中有改进的语法,我准备升级。

【问题讨论】:

  • 在我看来,没有比将 deleted.id 输出到 @tablevariable 更好的方法了

标签: sql-server tsql stored-procedures


【解决方案1】:

我同意 Shakeer Mirza 的评论,即不可避免地将 OUTPUT 子句结果插入表中,因为这是在 T-SQL 中使用该值的唯一方法。除非您有单独的 procs 的特定原因,否则您可以像下面的示例那样进行重构,恕我直言,它的味道稍微不那么臭。

CREATE PROCEDURE [jobs].[GetNextJob]        
AS

DECLARE @Job TABLE ( JobID int PRIMARY KEY );

DELETE TOP(1) FROM jobs.JobQueue WITH (ROWLOCK, READPAST)
OUTPUT deleted.JobID INTO @Job(JobID);

UPDATE jobs.Jobs set IsInQueue = 0 
OUTPUT inserted.*
WHERE JobID = (SELECT JobID from @Job);
GO

请注意,DELETE TOP 没有定义顺序,因此,如果您需要 FIFO,请考虑在 DELETE 中使用带有 ORDER BY 的子查询。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-22
    • 2021-11-21
    • 2011-12-03
    • 2013-08-06
    • 2011-10-24
    • 1970-01-01
    • 2013-02-09
    • 2012-02-17
    相关资源
    最近更新 更多