将查询抽象到存储过程会使其运行速度非常慢

时间:2015-06-08 13:14:25

标签: sql-server tsql stored-procedures

我有一个非常长的存储过程,其中包含许多逻辑块,可插入到不同的表中。这是一个这样的块

我的下表中有'data'

的唯一约束
[id] [int] IDENTITY(1,1) NOT NULL
[data] [varchar](512) NULL

此块尝试向“data”插入值。如果该值是唯一的,则插入它。在所有情况下,都会返回相关的数据ID

BEGIN TRY 
    INSERT INTO Data SELECT @data; 
END TRY 
BEGIN CATCH 
END CATCH   
SET @data_id = (SELECT id FROM Data WHERE data = @data); 

当我在原始存储过程中包含此代码块时,它运行正常。然而,为了整洁I和DRY,我认为我将它抽象为子过程,因为在其他一些SP中调用相同的块

ALTER PROCEDURE [dbo].[q_Data_TryInsert]

   @data nvarchar(512),
   @id INT OUTPUT

AS
BEGIN

    BEGIN TRY 
        INSERT INTO Data SELECT @data; 
    END TRY 
    BEGIN CATCH 
    END CATCH   
    SET @id = (SELECT id FROM Data WHERE data = @data);     

END

然后我将这个抽象的SP称为

EXEC [q_Data_TryInsert] @data, @data_id OUTPUT

抽象的SP会使整个过程减慢几个数量级,即使代码是相同的。

为什么会这样?

3 个答案:

答案 0 :(得分:1)

INSERT INTO [PKvalue] ([value])
select 'Data6' as [value] 
 where not exists (select top 1 ID from [PKvalue] where [value] = 'Data6');
select top 1 ID from [PKvalue] where [value] = 'Data6';

INSERT INTO data (data)
select @dtata as [data] 
 where not exists (select top 1 ID from [data] where [data] = @data);
select top 1 ID from [data] where [data] = '@data;

甚至不需要交易。该插入是一个事务。即使在选择之前发生了另一个插入,您仍然会得到正确的答案。只有删除或更新才能破坏选择。交易有开销。

答案 1 :(得分:1)

测试data,保存@id。如果需要,请插入@data。如果需要,请更新@id

BEGIN TRANSACTION
  DECLARE @output TABLE (id int)

  SELECT @id = id FROM #Data WHERE data = @data

  INSERT Data (data)
  OUTPUT inserted.[id] INTO @output
  SELECT @data
  WHERE @id IS NULL

  SELECT TOP 1 @id = id FROM @output
COMMIT TRANSACTION

答案 2 :(得分:0)

请更改

INSERT INTO Data SELECT @data; 

INSERT INTO Data (data)
 VALUES (@data)

并改变

SET @data_id = (SELECT id FROM Data WHERE data = @data); 

SET @data_id = IDENT_CURRENT('Data')

修改 为了得到你需要的东西,商店程序需要以这种方式重新加工

ALTER PROCEDURE [dbo].[q_Data_TryInsert]

   @data nvarchar(512),
   @id INT OUTPUT

AS
BEGIN
  IF NOT EXISTS(SELECT id FROM Data WHERE data = @data)
   BEGIN
    INSERT INTO Data (data) Values (@data) 
    SET @data_id = IDENT_CURRENT('Data')    
   END
  ELSE
    SET @id = (SELECT id FROM Data WHERE data = @data);     

END