Является ли курсор единственной альтернативой для выполнения такого рода операций? - PullRequest
4 голосов
/ 21 сентября 2011

Я пытаюсь оптимизировать длинную транзакцию, и я видел, что несколько раз делается следующее:

Declare @myCursor CURSOR FAST_FORWARD FOR
SELECT field1, MIN(COALESCE(field2, -2)) FROM MyTable tempfact
LEFT JOIN MyTable sd
ON tempfact.ID = sd.ID AND sd.TransactionId = @transactionId
WHERE tempfact.SomeField IS NULL
AND tempfact.TransactionId = @transactionId
GROUP BY tempfact.field1

OPEN @myCursor

FETCH NEXT FROM @myCursor INTO @field1Variable, @field2Variable

WHILE @@FETCH_STATUS = 0
BEGIN
   EXEC USP_SOME_PROC @field1Variable, @field2Variable
   FETCH NEXT FROM @myCursor INTO @field1Variable, @field2Variable
END

CLOSE @myCursor
DEALLOCATE @myCursor

Код для sproc USP_SOME_PROC выглядит следующим образом:

IF NOT EXISTS (SELECT * FROM SomeTable WHERE Field1 = @field1)
BEGIN
   INSERT INTO SomeTable (Field1, Field2)
   VALUES (@field1, @field2)
END

Как я уже говорил, это делается во многих местах, используемые таблицы и поля различны, но идея остается той же, и я уверен, что может быть способ повысить производительность этих sprocs, если курсоры не и, вероятно, ускоряя эту транзакцию, мы можем решить проблему с тупиком (тема для другого сообщения).

Ответы [ 3 ]

4 голосов
/ 21 сентября 2011

Вы можете использовать MERGE для этого

;WITH Source AS
(
SELECT field1,
       MIN(COALESCE(field2, -2)) as field2
FROM   MyTable tempfact
       LEFT JOIN MyTable sd
         ON tempfact.ID = sd.ID
            AND sd.TransactionId = @transactionId
WHERE  tempfact.SomeField IS NULL
       AND tempfact.TransactionId = @transactionId
GROUP  BY tempfact.field1  
)
MERGE SomeTable AS T
USING Source S
ON (T.Field1 = S.Field1)


WHEN NOT MATCHED BY TARGET THEN
    INSERT (Field1, Field2)
    VALUES (field1, field2)
    ;
1 голос
/ 21 сентября 2011

У меня не было возможности проверить это, но это должно быть близко: вам нужно вставить из оператора SELECT, но также нужно убедиться, что соответствующая запись еще не существует в SomeTable

INSERT INTO SomeTable (Field1, Field2)
SELECT field1, MIN(COALESCE(field2, -2)) 
FROM MyTable tempfact 
    LEFT JOIN MyTable sd ON tempfact.ID = sd.ID AND sd.TransactionId = @transactionId 
    LEFT JOIN SomeTable st ON st.Field1 = tempfact.field1
WHERE tempfact.SomeField IS NULL 
    AND tempfact.TransactionId = @transactionId 
    AND st.Field1 IS NULL
GROUP BY tempfact.field1 
0 голосов
/ 21 сентября 2011

Вам не нужен курсор и вы можете использовать логику массовой вставки, как показано ниже

INSERT INTO SomeTable (Field1, Field2) 
SELECT 
       field1,       
       MIN(COALESCE(field2, -2)) 
FROM
      MyTable tempfact        
LEFT JOIN 
      MyTable sd          
           ON tempfact.ID = sd.ID             
              AND sd.TransactionId = @transactionId 
WHERE  
      tempfact.SomeField IS NULL        
      AND tempfact.TransactionId = @transactionId 
GROUP  BY 
      tempfact.field1

Надеюсь, это поможет !!

...