我有一个非常长的存储过程,其中包含许多逻辑块,可插入到不同的表中。这是一个这样的块
我的下表中有'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会使整个过程减慢几个数量级,即使代码是相同的。
为什么会这样?
答案 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