防止变量在SQL Server中内联

时间:2014-08-14 22:59:45

标签: sql sql-server

我在存储过程中遇到了一个问题,它将数据从一个表递增复制到另一个表:

DECLARE @StartId bigint;

SELECT @StartId = COALESCE(MAX(Id), 0) 
FROM dbo.TargetTable WITH (NOLOCK);

INSERT INTO dbo.TargetTable (...)
   SELECT ... 
   FROM dbo.SourceTable
   WHERE Id > @StartId

这个存储过程被绞死超过15分钟,我将其杀死。但是,如果我分开运行这两个部分,

SELECT COALESCE(MAX(Id), 0) 
FROM dbo.TargetTable WITH (NOLOCK);

它会立即返回头部ID,例如100000。

然后我在@StartId语句中将INSERT变量替换为100000并运行它,

INSERT INTO dbo.TargetTable (...)
   SELECT ... 
   FROM dbo.SourceTable
   WHERE Id > 100000

此部分在不到几秒钟内完成。

似乎在原始存储过程中,变量@StartId被内联到INSERT语句中,从而导致死锁。

我知道可能有更好的方法或解决方法,例如将进度存储在第三个表中,但是,我的问题是我可以在输入INSERT语句之前强制对变量进行评估吗?

编辑:由于这是在存储过程中,我没有选择使用GO。

2 个答案:

答案 0 :(得分:1)

我刚刚发现原因并非内联变量表达式,而是涉及变量的执行计划问题。

已经有了Q / A,应用OPTION(RECOMPILE)的答案对我很有用:

SQL Server Query: Fast with Literal but Slow with Variable

答案 1 :(得分:-2)

这可能看起来很直接,但你可以把它们放在两个不同的交易中......所以首先你要做你的

  BEGIN TRANSACTION GetMax
SELECT COALESCE(MAX(Id), 0) FROM dbo.TargetTable WITH (NOLOCK);
GO
 INSERT INTO dbo.TargetTable (...)
 SELECT ... 
  FROM dbo.SourceTable
  WHERE Id > 100000
GO
COMMIT TRANSACTION GetMax;
GO
你能试试吗?