|
因工作需要,用EXCEL+ADO+SQL SERVER編寫了一個(gè)加班工資錄入的小程序。寫好后進(jìn)行了一些測(cè)試,因測(cè)試數(shù)據(jù)不多,沒發(fā)現(xiàn)有什么問題。這個(gè)月正式用這個(gè)程序來計(jì)算加班工資并上傳,一共1000多條記錄,運(yùn)行上傳,花了很長時(shí)間程序還是沒有響應(yīng),開始以為是程序有問題,調(diào)試后發(fā)現(xiàn)程序本身并沒有失去響應(yīng),只是速度非常慢,測(cè)試了一下,更新10條記錄平均一下要3秒,這樣1000多條記錄的話差不多要5分鐘,于是開始查找原因。 先簡(jiǎn)單說一下程序工作的方法,因要連接到SQL SERVER數(shù)據(jù)庫,所以上傳附件也不是太能說明問題,而且最終發(fā)現(xiàn)解決問題的關(guān)鍵也不需要上傳附件。我的程序使用ADO建立一個(gè)connection對(duì)象cnGzb和一個(gè)recordset對(duì)象rsGzb,通過SQL語句將數(shù)據(jù)讀入rsGzb,加班信息存放在一張工作表中,遍歷每條加班數(shù)據(jù),將加班工資更新rsGzb中相應(yīng)的記錄(使用recordset的filter屬性根據(jù)工號(hào)進(jìn)行篩選),最后用recordset的updatebatch方法更新SQL Server數(shù)據(jù)庫表中的相應(yīng)字段。 首先我打算先找出哪些代碼影響了速度,我先把覺得可能影響速度的代碼注釋掉,再運(yùn)行,最終發(fā)現(xiàn)影響速度的是recordset的filter屬性,可能是filter的速度比較慢而的引起的,于是就想是否能找到一個(gè)更快的查找方法,發(fā)現(xiàn)ADO中還有一個(gè)find方法。修改代碼為find后速度還是沒有太大的改變,郁悶... 怎么辦呢?突然想起以看過一遍關(guān)于優(yōu)化SQL查詢的文章,里面對(duì)SQL查詢優(yōu)化有一個(gè)比較詳細(xì)的說明,特別比較了在已建立索引的字段上進(jìn)行查詢與未建立索引字段上查詢速度的差別,想起一句話,“所有快速查找都是基于排序的”,于是馬上修改代碼,添加對(duì)rsGzb中的工號(hào)字段進(jìn)行排序代碼(rsGzb.Sort = "gh ASC"),運(yùn)行,出錯(cuò)(運(yùn)行時(shí)錯(cuò)誤3251:當(dāng)前提供程序不支持排序或過濾所必須的界面),查看sort屬性的幫助,發(fā)現(xiàn)里面有一條說明“此屬性要求將 CursorLocation 屬性設(shè)置為 adUseClient?!保谑翘砑哟a(cnGzb.CursorLocation = adUseClient),再運(yùn)行。太爽了,1秒內(nèi)就完成了操作,太有成就感了!\(^O^)/ 沒想到排序可以把查找的數(shù)據(jù)提高到這么恐怖的程度。太厲害了。 馬上想到把這個(gè)經(jīng)過到壇子里來發(fā)貼,和大家分享一下。 為了能很好的表達(dá)這個(gè)意思,也讓大家感覺一下前后的差別,于是想到利用recordset的save方法把recordset保存到文件中,這樣就可以脫開SQLSERVER,大家就可以在沒有數(shù)據(jù)庫連接的情況下進(jìn)行測(cè)試了。修改代碼,保存recrodset。完成。 進(jìn)行測(cè)試,把排序的代碼注釋掉,運(yùn)行。咦,不到1秒就完成了,怎么回事,難道注銷的代碼行搞錯(cuò)了,反復(fù)檢查發(fā)現(xiàn)排序的代碼的確是注釋掉了,反復(fù)測(cè)試發(fā)現(xiàn)似乎排序?qū)Τ绦虻倪\(yùn)行影響不大,那到底是怎么回事呢? 想了很久終于明白了,提高速度的那行代碼是(cnGzb.CursorLocation = adUseClient), CursorLocation屬性是一個(gè)connect和recordset對(duì)象都有的一個(gè)屬性,該屬性表示如何存儲(chǔ)查詢結(jié)果,默認(rèn)值為AdUseServer。若不對(duì)recordset的CursorLocation進(jìn)行設(shè)置,則recordset將繼承connection對(duì)象的CursorLocation值。 在默認(rèn)情況下recordset對(duì)象對(duì)于查詢的結(jié)果由OLE DB提供程序或數(shù)據(jù)庫來管理,簡(jiǎn)單理解為recordset的查詢結(jié)果存放于服務(wù)器端,而且處理這些查詢結(jié)果的過程要通過OLE DB或數(shù)據(jù)庫來完成而不是通過ADO來完成,這時(shí)候ADO更象一個(gè)任務(wù)派發(fā)者,指揮OLE DB或數(shù)據(jù)庫來完成工作,這樣一來,一個(gè)命令下達(dá)后,影響這個(gè)命令執(zhí)行的因素就很多了,如OLE DB或數(shù)據(jù)庫的響應(yīng)速度,網(wǎng)絡(luò)連接等等,我當(dāng)時(shí)由于數(shù)據(jù)庫在其他的服務(wù)器上,因?yàn)榭赡芫W(wǎng)絡(luò)連接引起的速度變慢可以也是其中的一個(gè)因素。當(dāng)把CursorLocation設(shè)置為adUseClient時(shí),查詢結(jié)果直接存放于recordset的臨時(shí)表中(本地),由ADO直接對(duì)recordset進(jìn)行操作,這時(shí)前面的影響因素就沒有了,處理的速度直接取決于本機(jī)速度。這就是我所碰到的問題的關(guān)鍵。 把這個(gè)經(jīng)過記錄下來是為了和大家分享一下我從發(fā)現(xiàn)問題到分析問題到解決問題的過程,可能對(duì)大家有所幫助。 下面就是程序中的那幾句關(guān)鍵代碼(第1名和第3句在這兒的作用相同,可以只寫一句) cnGzb.CursorLocation = adUseClient Set rsGzb = New ADODB.Recordset rsGzb.CursorLocation = adUseClient 'CursorLocation對(duì)于關(guān)閉的recordset對(duì)象可讀可寫,對(duì)于打開的recordset對(duì)象只讀 rsGzb.Open sSqlCommand, cnGzb, adOpenKeyset, adLockBatchOptimistic [ 本帖最后由 lbpp 于 2009-6-5 12:52 編輯 ] |
|
|