在業務系統應用中,經常會使用到大量數據的的提交(包括查詢、更新或刪除),如果目標數據庫的數據量較大,一次需要處理的操作較多,就會出現系統執行效率低下等問題。文本以Oracle9i數據庫為例,通過對ADO.Net中的數據庫支持的應用實踐,說明幾種常見的優化處理方法,並對比其中的優劣。
為了說明情況,以某業務數據填報功能為例,假設有100個用戶每周需要填報某統計數量,填報明細的數據量約為200條,有專門的填報頁面實現一次提交,這樣一周的數據增量約為2萬,一年為100多萬,要保證系統有效運行6年以上,需要考慮數據存儲(增、刪、改)效率問題,(數據庫本身的優化配置,包括表空間、索引等查詢效率已經考慮,不在此討論范疇)。這類業務的特點是,數據操作量較大,但執行的指令復雜度較低,包含簡單的新增、修改、刪除3類。
對每一個要處理的操作,直接對目標表執行對應的SQL操作(或存儲過程),可使用ADO.Net的參數化SQL或通過DataSet與DataAdapter來間接處理。這樣每個用戶批量提交數據時,需要執行大約200次SQL操作,雖然數據庫進行了優化,單次執行SQL的效率並不低,但由於一次執行的指令較多,隨著目標數據容量的增加,效率會逐步降低,最終不可忍受。
對於大規模的目標數據庫表,進行多次修改、刪除或更新操作,效率必定較慢,要降低對目標表的操作次數,可以采用臨時表的解決辦法。具體方法為:建立一個與目標表結構類似的臨時表(由於B/S模式的特點,臨時表是基於事務的,而不是基於連接的),並增加操作模式標記字段,在執行操作前,將本次要操作的數據,就是某個用戶,每周的數據(約200條左右,第一次處理時應該沒有數據)一次查詢轉入臨時表,再對臨時表執行修改、更新、刪除(作刪除標記)操作,處理完畢後,分別將臨時表的數據分三類提交到目標表。流程如下圖所示:
刪除
Delete From TARGET_TABLE Where KEY In(Select KEY
From TEMP_TABLE
新增
Insert Into TARGET_TABLE …
Select … From TEMP_TABLE
修改
Update TARGET_TABLE Set …
Where KEY=TEMP_TABLE.KET AND TEMP_TABLE.STATE=’Update’
實驗證明,在50萬數據量的條件下,此方法能比傳統的方法快40倍左右,且執行效率受目標數據庫容量的影響較小。
System.Data.OracleClIEnt 的ADO.Net 2.0版本支持第一種方式的的批處理,如通過DataAdapter對DataSet的批量數據提交時,系統會根據數據集合中的新增,修改,刪除標識,構造批處理指令,形成SQL指令段,提交服務器執行。這種方式是將多個SQL指令形成一組SQL指令的方法,實現多個指令的批執行,能一定程度提高功能的執行效率。原理如下所示:
Begin
Insert Into TAREGT_TABLE(A,B,C) Values(:1,:2,:3);
Insert Into TAREGT_TABLE(A,B,C) Values(:4,:5,:6);
Insert Into TAREGT_TABLE(A,B,C) Values(:7,:8,:9);
……
Insert Into TAREGT_TABLE(A,B,C) Values(:n,:n+1,:n+2);
end;
此方法形成的批處理SQL指令及參數會隨著數據量的增加而成倍增加,數據更新量與執行效率受到限制。而微軟的Oracle ADO.Net實現並沒有將批處理方法直接對外公開,只能通過DataSet的數據批量更新間接使用。
另一種處理方法是使用Oracle的ADO.Net實現。Oracle.DataAccess.ClIEnt實現的ADO.Net支持第二種模式的批處理指令,其利用Oracle數據庫自帶的批處理功能,通過設定OracleCommand的ArrayBindCount來實現對參數數組的傳遞。當ArrayBindCount設置為大於1時,傳遞給一個OracleCommand的參數不再是參數值,而是參數數組,這樣,一條Command指令就可以執行多個處理,如:插入100條數據。使用這種方法,利用了數據庫本身對批量數據操作的優化機制,極大提高了數據操作效率。通過對目標數據庫容量為50萬的目標表測試發現,此方法執行比傳統方法的執行效率提高50倍以上,在測試過程中發現,100萬的目標數據量的情況下,一次插入1萬條數據,只需要1秒左右,且操作效率受目標數據量的影響較小。
綜合以上分析,我們認為,采用臨時表的方法及批處理的手段都能較好解決大規模數據量模式下的批量數據提交的問題。其中,Oracle的ADO.Net的實現效率最高,處理最簡單,微軟ADO.Net2.0的實現沒有完全利用數據庫本身的功能,功能及效率受到局限。而臨時表的處理方法編程比較復雜,適合於在使用微軟的ADO.Net的情況下使用。更進一步,Oracle存儲過程支持參數數組的傳遞,也可以采用通過傳遞參數數組的存儲過程來實現,前提也是必須采用Oracle的ADO.Net實現,因為微軟的ADO.Net實現不支持參數數組傳遞;而Oracle數據庫也支持Bulk Insert功能,如果有批量的數據需要插入,可以考慮使用此方法,此處不詳細討論。