1. 程式人生 > >SQL Server中用While迴圈替代遊標(Cursor)的解決方案

SQL Server中用While迴圈替代遊標(Cursor)的解決方案

By行處理資料,推薦2種方式:

1、遊標

2、While迴圈

我們來了解下這兩種方案處理1w行資料分別需要多長時間。

一、遊標。

首先我們填充一個表,用優雅的遞迴方式填充。

複製程式碼
create table Orders(OrderID int,CostValue decimal(18,2) )

;with cte_temp
as
(
    select 1 as OrderID
    union all
    select OrderID+1 from cte_temp where OrderID<10000
)

insert into Orders(OrderID)
select
OrderID from cte_temp option (maxrecursion 32767);
複製程式碼

 現在我們的訂單表Orders有了一萬條訂單,但是CostValue還是NULL值。

我們用遊標的方式給每一條訂單新增一個CostValue,耗時44s

複製程式碼
--遊標
DECLARE @OrderID int

DECLARE cursor_CostValue CURSOR FOR  SELECT OrderID FROM Orders
OPEN cursor_CostValue
FETCH NEXT FROM cursor_CostValue INTO @OrderID
WHILE
@@FETCH_STATUS = 0 BEGIN UPDATE Orders SET CostValue = OrderID+100 WHERE OrderID = @OrderID FETCH NEXT FROM cursor_CostValue INTO @OrderID END CLOSE cursor_CostValue DEALLOCATE cursor_CostValue
複製程式碼

 二、While迴圈

將資料放在臨時表中,然後操作臨時表,最後更新回總表。耗時16s

複製程式碼
DECLARE @RowID int
      
--    獲取待處理的資料記錄到臨時表
--
欄位說明:RowID:記錄行號 / DealFlg:行處理標識 SELECT RowID = IDENTITY(INT , 1, 1),DealFlg=0,OrderID,CostValue = 0 INTO #Tmp FROM Orders SELECT @RowID = MIN(RowID) FROM #Tmp WHERE DealFlg = 0 -- 若最小行號不為空(有需要處理的資料) WHILE @RowID IS NOT NULL BEGIN UPDATE #Tmp SET DealFlg = 1,CostValue=OrderID+100 WHERE RowID = @RowID SELECT @RowID = MIN(RowID) FROM #Tmp WHERE DealFlg = 0 END update O set O.CostValue=T.CostValue from Orders O inner join #Tmp T on O.OrderID=T.OrderID
複製程式碼

還有一種錯誤的While迴圈,即不把資料放在臨時表中,直接操作本表,會大大增加耗時。

因為多次呼叫本表,如果在生產環境,將是一個災難。

複製程式碼
DECLARE @OrderID INT   
--表中OrderID最小的值
SELECT @OrderID = MIN(OrderID) FROM Orders where CostValue is null
WHILE @OrderID IS NOT NULL
BEGIN
    UPDATE Orders SET CostValue = OrderID+100 WHERE OrderID = @OrderID
    SELECT @OrderID = MIN(OrderID) FROM Orders where CostValue is null
END
複製程式碼

參考連結:http://www.cnblogs.com/swq6413/archive/2012/09/01/2667190.html