在日常的業(yè)務(wù)系統(tǒng)應(yīng)用中,大家經(jīng)常會(huì)使用到大量數(shù)據(jù)的的提交(包括查詢、更新或刪除),假如目標(biāo)數(shù)據(jù)庫(kù)的數(shù)據(jù)量較大,一次需要處理的操作較多,就會(huì)出現(xiàn)系統(tǒng)執(zhí)行效率低下等問(wèn)題。文本中筆者以O(shè)racle9i數(shù)據(jù)庫(kù)為例,通過(guò)對(duì)ADO.Net中的數(shù)據(jù)庫(kù)支持的應(yīng)用實(shí)踐,說(shuō)明幾種常見(jiàn)的優(yōu)化處理方法,并對(duì)比其中的優(yōu)劣。 為了更詳細(xì)說(shuō)明情況,筆者以某業(yè)務(wù)數(shù)據(jù)填報(bào)功能為例,假設(shè)有100個(gè)用戶每周需要填報(bào)某統(tǒng)計(jì)數(shù)量,填報(bào)明細(xì)的數(shù)據(jù)量約為200條,有專門(mén)的填報(bào)頁(yè)面實(shí)現(xiàn)一次提交,這樣一周的數(shù)據(jù)增量約為2萬(wàn),一年為100多萬(wàn),要保證系統(tǒng)有效運(yùn)行6年以上,需要考慮數(shù)據(jù)存儲(chǔ)(增、刪、改)效率問(wèn)題,(數(shù)據(jù)庫(kù)本身的優(yōu)化配置,包括表空間、索引等查詢效率已經(jīng)考慮,不在此討論范疇)。這類業(yè)務(wù)的特點(diǎn)是,數(shù)據(jù)操作量較大,但執(zhí)行的指令復(fù)雜度較低,包含簡(jiǎn)單的新增、修改、刪除3類。 傳統(tǒng)處理方法存在的問(wèn)題 對(duì)每一個(gè)要處理的操作,直接對(duì)目標(biāo)表執(zhí)行對(duì)應(yīng)的SQL操作(或存儲(chǔ)過(guò)程),可使用ADO.Net的參數(shù)化SQL或通過(guò)DataSet與DataAdapter來(lái)間接處理。這樣每個(gè)用戶批量提交數(shù)據(jù)時(shí),需要執(zhí)行大約200次SQL操作,雖然數(shù)據(jù)庫(kù)進(jìn)行了優(yōu)化,單次執(zhí)行SQL的效率并不低,但由于一次執(zhí)行的指令較多,隨著目標(biāo)數(shù)據(jù)容量的增加,效率會(huì)逐步降低,最終不可忍受。 優(yōu)化方法1:臨時(shí)表處理模式 對(duì)于大規(guī)模的目標(biāo)數(shù)據(jù)庫(kù)表,進(jìn)行多次修改、刪除或更新操作,效率必定較慢,要降低對(duì)目標(biāo)表的操作次數(shù),可以采用臨時(shí)表的解決辦法。具體方法為:建立一個(gè)與目標(biāo)表結(jié)構(gòu)類似的臨時(shí)表(由于B/S模式的特點(diǎn),臨時(shí)表是基于事務(wù)的,而不是基于連接的),并增加操作模式標(biāo)記字段,在執(zhí)行操作前,將本次要操作的數(shù)據(jù),就是某個(gè)用戶,每周的數(shù)據(jù)(約200條左右,第一次處理時(shí)應(yīng)該沒(méi)有數(shù)據(jù))一次查詢轉(zhuǎn)入臨時(shí)表,再對(duì)臨時(shí)表執(zhí)行修改、更新、刪除(作刪除標(biāo)記)操作,處理完畢后,分別將臨時(shí)表的數(shù)據(jù)分三類提交到目標(biāo)表。流程如下圖所示: 刪除 Delete From TARGET_TABLE Where KEY In(Select KEY From TEMP_TABLE Where STATE=‘Delete’ 新增 Insert Into TARGET_TABLE … Select … From TEMP_TABLE Where STATE=‘Insert’ 修改 Update TARGET_TABLE Set … Where KEY=TEMP_TABLE.KET AND TEMP_TABLE.STATE=‘Update’ 實(shí)驗(yàn)證明,在50萬(wàn)數(shù)據(jù)量的條件下,此方法能比傳統(tǒng)的方法快40倍左右,且執(zhí)行效率受目標(biāo)數(shù)據(jù)庫(kù)容量的影響較小。 優(yōu)化方法2:使用SQL批處理
SQL批處理一般有2種模式:一種是將要執(zhí)行的SQL語(yǔ)句,連接形成批處理指令,一次提交到服務(wù)器執(zhí)行;一種是對(duì)執(zhí)行的SQL指令,傳遞多組參數(shù),批執(zhí)行。這兩種方法都需要數(shù)據(jù)庫(kù)及ADO.Net的支持。 System.Data.OracleClient 的ADO.Net 2.0版本支持第一種方式的的批處理,如通過(guò)DataAdapter對(duì)DataSet的批量數(shù)據(jù)提交時(shí),系統(tǒng)會(huì)根據(jù)數(shù)據(jù)集合中的新增,修改,刪除標(biāo)識(shí),構(gòu)造批處理指令,形成SQL指令段,提交服務(wù)器執(zhí)行。這種方式是將多個(gè)SQL指令形成一組SQL指令的方法,實(shí)現(xiàn)多個(gè)指令的批執(zhí)行,能一定程度提高功能的執(zhí)行效率。原理如下所示: 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指令及參數(shù)會(huì)隨著數(shù)據(jù)量的增加而成倍增加,數(shù)據(jù)更新量與執(zhí)行效率受到限制。而微軟的Oracle ADO.Net實(shí)現(xiàn)并沒(méi)有將批處理方法直接對(duì)外公開(kāi),只能通過(guò)DataSet的數(shù)據(jù)批量更新間接使用。
另一種處理方法是使用Oracle的ADO.Net實(shí)現(xiàn)。Oracle.DataAccess.Client實(shí)現(xiàn)的ADO.Net支持第二種模式的批處理指令,其利用Oracle數(shù)據(jù)庫(kù)自帶的批處理功能,通過(guò)設(shè)定OracleCommand的ArrayBindCount來(lái)實(shí)現(xiàn)對(duì)參數(shù)數(shù)組的傳遞。當(dāng)ArrayBindCount設(shè)置為大于1時(shí),傳遞給一個(gè)OracleCommand的參數(shù)不再是參數(shù)值,而是參數(shù)數(shù)組,這樣,一條Command指令就可以執(zhí)行多個(gè)處理,如:插入100條數(shù)據(jù)。使用這種方法,利用了數(shù)據(jù)庫(kù)本身對(duì)批量數(shù)據(jù)操作的優(yōu)化機(jī)制,極大提高了數(shù)據(jù)操作效率。通過(guò)對(duì)目標(biāo)數(shù)據(jù)庫(kù)容量為50萬(wàn)的目標(biāo)表測(cè)試發(fā)現(xiàn),此方法執(zhí)行比傳統(tǒng)方法的執(zhí)行效率提高50倍以上,在測(cè)試過(guò)程中發(fā)現(xiàn),100萬(wàn)的目標(biāo)數(shù)據(jù)量的情況下,一次插入1萬(wàn)條數(shù)據(jù),只需要1秒左右,且操作效率受目標(biāo)數(shù)據(jù)量的影響較小。
|