Является ли курсор единственной альтернативой для выполнения таких операций?
Я пытаюсь оптимизировать длинную транзакцию, и я видел, что следующее делается довольно много раз:
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 ответа
Ты можешь использовать 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)
;
У меня не было возможности проверить это, но это должно быть близко: вам нужно вставить из оператора 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
Вы не должны иметь курсор и можете использовать логику массовой вставки, как показано ниже
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
Надеюсь это поможет!!