1. 程式人生 > >SQL Server :While迴圈替代遊標,效能提升

SQL Server :While迴圈替代遊標,效能提升

在編寫SQL批處理或儲存過程程式碼的過程中,經常會碰到有些業務邏輯的處理,需要對滿足條件的資料記錄逐行進行處理,這個時候,大家首先想到的方案大部分是用“遊標”進行處理。

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

  我首先是採用“遊標”編寫的業務邏輯儲存過程,SQL程式碼可以如下:

複製程式碼
 1 DECLARE @ORDERID    VARCHAR(30)
 2 
 3 --    宣告區域性遊標:從訂單資料表獲取訂單日期為2012-09-01,訂單型別為Sales的訂單編號
4 DECLARE CURSOR_ORDER CURSOR LOCAL FOR 5 SELECT ORDERID FROM ORDERHD H WHERE ORDERDATE = '2012-09-01' AND H.ORDERTYPE = 'Sales' 6 7 -- 開啟遊標 8 OPEN CURSOR_ORDER 9 FETCH NEXT FROM CURSOR_ORDER INTO @ORDERID 10 WHILE @@FETCH_STATUS = 0 11 BEGIN 12 13 /* 14 此處編寫對當前行資料的業務邏輯處理程式碼 15 */
16 17 -- 得到下一條記錄 18 FETCH NEXT FROM CURSOR_ORDER INTO @ORDERID 19 END 20 21 -- 關閉遊標 22 CLOSE CURSOR_ORDER 23 -- 釋放遊標 24 DEALLOCATE CURSOR_ORDER
複製程式碼

   功能是實現了,但是客服在實際使用過程中,經常反饋批量操作效率太慢,需要等待較長時間才能完成操作。經過測試發現,速度慢在遊標逐行處理過程中,當需要處理的記錄數較大,而且遊標處理位於資料庫事務內時,速度非常慢。

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

  經不斷的嘗試,終於找到一個方法,那就是用WHILE迴圈來進行逐行資料處理。首先將需要處理的資料記錄獲取到一個臨時表(此臨時表包括2個重要欄位:REFID - 記錄行號,DealFlg:行處理標識,用1/0標識行是否已處理),然後WHILE迴圈對臨時表進行逐行處理,SQL程式碼如下:

複製程式碼
 1 DECLARE   @REFID        INT
 2         , @ORDERID        VARCHAR(30)
 3         
 4 --    獲取待處理的資料記錄到臨時表
 5 --    欄位說明:REFID:記錄行號 / DealFlg:行處理標識
 6 SELECT  REFID = IDENTITY(INT , 1, 1), DealFlg = 0, ORDERID
 7 INTO #Temp_Lists
 8 FROM ORDERHD
 9 WHERE ORDERDATE = '2012-09-01' AND H.ORDERTYPE = 'Sales'
10 
11 --    獲取臨時表資料的最小行號
12 SELECT @REFID = MIN(REFID) FROM #Temp_Lists WHERE DealFlg = 0
13 
14 --    若最小行號不為空(有需要處理的資料)
15 WHILE @REFID IS NOT NULL
16 BEGIN
17 
18     --    獲取當前處理行的資訊
19     SELECT @ORDERID = ORDERID FROM  #Temp_Lists WHERE REFID = @REFID
20 
21     /*     
22     此處編寫對當前行資料的業務邏輯處理程式碼        
23     */
24     
25     --    標識當前行已處理完畢
26     UPDATE #Temp_Lists SET DealFlg = 1 WHERE REFID = @REFID
27     
28     --    選擇下一行號
29     SELECT @REFID = MIN(REFID) FROM #Temp_Lists WHERE DealFlg = 0 AND REFID > @REFID
30 
31 END
複製程式碼

   經過這樣對原儲存過程進行修正後,批量操作速度得到顯著提升。

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

出處:http://www.cnblogs.com/chenxizhang/archive/2013/03/14/2959688.html