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

原文:https://www.cnblogs.com/swq6413/archive/2012/09/01/2667190.htmlhtml

在編寫SQL批處理或存儲過程代碼的過程當中,常常會碰到有些業務邏輯的處理,須要對知足條件的數據記錄逐行進行處理,這個時候,你們首先想到的方案大部分是用「遊標」進行處理。數據庫

  舉個例子,在訂單管理系統中,客服須要對訂單日期爲2012-09-01的銷售訂單進行某個批量操做,好比批量發貨操做,後臺業務邏輯處理時,須要對知足條件的訂單記錄進行逐行處理。測試

  我首先是採用「遊標」編寫的業務邏輯存儲過程,SQL代碼能夠以下:spa

遊標
DECLARE @ORDERID    VARCHAR(30)

--    聲明局部遊標:從訂單數據表獲取訂單日期爲2012-09-01,訂單類型爲Sales的訂單編號
DECLARE CURSOR_ORDER CURSOR LOCAL FOR  
    SELECT ORDERID FROM ORDERHD H WHERE ORDERDATE = '2012-09-01' AND H.ORDERTYPE = 'Sales'

--    打開遊標
OPEN CURSOR_ORDER
FETCH NEXT FROM CURSOR_ORDER INTO @ORDERID
WHILE @@FETCH_STATUS = 0
BEGIN

    /*
    此處編寫對當前行數據的業務邏輯處理代碼
    */

    --    獲得下一條記錄
    FETCH NEXT FROM CURSOR_ORDER INTO @ORDERID
END

--    關閉遊標
CLOSE CURSOR_ORDER  
--    釋放遊標
DEALLOCATE CURSOR_ORDER

  

   功能是實現了,可是客服在實際使用過程當中,常常反饋批量操做效率太慢,須要等待較長時間才能完成操做。通過測試發現,速度慢在遊標逐行處理過程當中,當須要處理的記錄數較大,並且遊標處理位於數據庫事務內時,速度很是慢。code

  那麼,有什麼方法能夠解決這個處理速度慢的問題嗎?htm

  經不斷的嘗試,終於找到一個方法,那就是用WHILE循環來進行逐行數據處理。首先將須要處理的數據記錄獲取到一個臨時表(此臨時表包括2個重要字段:REFID - 記錄行號,DealFlg:行處理標識,用1/0標識行是否已處理),而後WHILE循環對臨時表進行逐行處理,SQL代碼以下:blog

While 循環 DECLARE @REFID INT , @ORDERID VARCHAR(30) -- 獲取待處理的數據記錄到臨時表 --    字段說明:REFID:記錄行號 / DealFlg:行處理標識 SELECT REFID = IDENTITY(INT , 1, 1), DealFlg = 0, ORDERID INTO #Temp_Lists FROM ORDERHD WHERE ORDERDATE = '2012-09-01' AND H.ORDERTYPE = 'Sales'

-- 獲取臨時表數據的最小行號 SELECT @REFID = MIN(REFID) FROM #Temp_Lists WHERE DealFlg = 0

-- 若最小行號不爲空(有須要處理的數據) WHILE @REFID IS NOT NULL BEGIN -- 獲取當前處理行的信息 SELECT @ORDERID = ORDERID FROM  #Temp_Lists WHERE REFID = @REFID /* 此處編寫對當前行數據的業務邏輯處理代碼 */
    
    -- 標識當前行已處理完畢 UPDATE #Temp_Lists SET DealFlg = 1 WHERE REFID = @REFID -- 選擇下一行號 SELECT @REFID = MIN(REFID) FROM #Temp_Lists WHERE DealFlg = 0 AND REFID > @REFID END

 

通過這樣對原存儲過程進行修正後,批量操做速度獲得顯著提高。事務

  有興趣的朋友,能夠嘗試使用這個方法替代遊標,對比2種方案的處理效率。class

相關文章
相關標籤/搜索