2015-06-08 4 views
0

У меня очень длинная хранимая процедура с несколькими блоками логики в ней, которые вставляются в разные таблицы. Вот один такой блокУточнение запроса к хранимой процедуре заставляет его работать очень медленно

У меня следующую таблицу с уникальным ограничением на

[id] [int] IDENTITY(1,1) NOT NULL 
[data] [varchar](512) NULL 

Этот блок попыток «данные», чтобы вставить значение «данные». если это значение уникально, оно вставлено. Во всех случаях соответствующий идентификатор данных возвращается

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, я думал, что я абстрактный его к югу от процедуры, так как тот же блок называется в нескольких другом SPs

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 замедляет весь процесс на несколько порядков, даже если код тот же.

Почему это происходит?

+5

У вас никогда не должно быть исключения «ловить» в вашем нормальном логическом потоке. (Таким образом, почему это называется «исключение» .. оно должно быть исключительным (редким). Положите проверку наличия внутри вашего INSERT. »If not exists (выберите null из Data, где data = @data) begin/* insert here */END. – granadaCoder

+2

Ю. может захотеть также взглянуть на scope_identity, это избавит вас от необходимости выбрать @id –

+0

Что показывает план выполнения как самый медленный элемент в медленном запросе? –

ответ

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') 

EDIT: , чтобы получить то, что вам нужно процедура магазина должна быть переработана таким образом

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 
+0

Это не устраняет проблему, если @data уже присутствует – Paparazzi

+0

Если запись уже существует, это не вернет идентификатор. Работает только для вставок. Хотя я мог бы поместить его в блок try catch, который ускорил бы все в этом случае. Так что спасибо. – roryok

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; 

даже не нужна транзакция. Эта вставка - это транзакция. Даже если другая вставка произошла до выбора, вы все равно получите правильный ответ. Только удаление или обновление могут нарушить выбор. У транзакции есть накладные расходы.

+0

это правда, даже если у меня есть несколько потоков, выполняющих этот оператор SQL? – roryok

+0

Сделка - сделка. – Paparazzi

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 
Смежные вопросы