开发者

Is a cursor the only alternative to do this kind of operation

I'm trying to optimize a long transaction and I've seen that the following is done quite a few times:

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

The code for the USP_SOME_PROC sproc is as follows:

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

Like I mentioned this is done in quite a few places, tables and fields involved are different but the idea remains the same, and I'm su开发者_如何学Cre that there might be a way to increase the performance of these sprocs if cursors are not used and probably by making this transaction faster an issue that we're having with a deadlock (a subject for another post) might be solved.


You can use MERGE for this

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


I haven't had a chance to test this, but this should be close: you need to insert from a SELECT statement but also need to make sure that a corresponding record doesn't already exist in 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 


You need not have a cursor and can use bulk insert logic something like below

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

Hope this helps!!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜