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

 By行處理數據,推薦2種方式:

一、遊標html

二、While循環post

咱們來了解下這兩種方案處理1w行數據分別須要多長時間。code

1、遊標。htm

首先咱們填充一個表,用優雅的遞歸方式填充。blog

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。ci

--遊標
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

 

 2、While循環it

將數據放在臨時表中,而後操做臨時表,最後更新回總表。耗時16s。io

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循環,即不把數據放在臨時表中,直接操做本表,會大大增長耗時。table

由於屢次調用本表,若是在生產環境,將是一個災難。

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
相關文章
相關標籤/搜索