注冊(cè) 登錄
Office中國(guó)論壇/Access中國(guó)論壇 返回首頁

的個(gè)人空間 http://ctxi.cn/?0 [收藏] [復(fù)制] [分享] [RSS]

日志

編碼提示與優(yōu)化技巧

已有 631 次閱讀2007-9-2 23:20 |個(gè)人分類:我的作品

1. 使用Option Explicit

    一定要使用Option Explicit。Option Explicit 要求確定所有變量的大小,要不然VBA就會(huì)用最大、最靈活的數(shù)據(jù)類型來保存變量。通常來講,規(guī)模很大、靈活性很強(qiáng)的應(yīng)用也是最慢的。

2.  慎重選擇變量大小
       在確定變量大小時(shí),使用盡可能最小的變量尺寸。在整型就可以時(shí)不要使用雙精度型,可能情況下使用固定長(zhǎng)度字符串而不要使用可變長(zhǎng)度字符串。

3.  使用字符串變量以節(jié)省堆棧空間

     字符串變量是代碼中最常用的一種數(shù)據(jù)類型,它們可以被分解成三種類型:
     . 局部固定長(zhǎng)度(長(zhǎng)度不超過64個(gè)字符)——這些字符串每個(gè)字符僅用兩個(gè)字節(jié),而且不使用堆空間。
     . 局部固定長(zhǎng)度(長(zhǎng)度超過65個(gè)字符)——這些字符串每個(gè)字符仍然使用兩個(gè)字節(jié),但是在堆內(nèi)存中。同時(shí),它們還要求堆棧中的四個(gè)字節(jié)來指向堆中的變量。
     .局部可變量長(zhǎng)度(長(zhǎng)度一限)——堆空間的數(shù)量依存字符串長(zhǎng)度而定。四字節(jié)的堆棧內(nèi)存被用指向堆中變量的指針。
   在處理字符串時(shí),目標(biāo)就應(yīng)該是減少正在使用的堆棧內(nèi)存。嘗試著把字符串轉(zhuǎn)換成局部可變長(zhǎng)度或靜態(tài)固定長(zhǎng)度字符串。下面的代碼段舉說明為了節(jié)省堆棧內(nèi)存而把內(nèi)存而把可變長(zhǎng)度字符串重新聲明為靜態(tài)固定長(zhǎng)度字符串。

     Dim strstring as string


     Static strstring as string*30


     提示:用表的字段大小來決定固定寬度文本字符串的長(zhǎng)度

4.特寫的對(duì)象類型聲明

    在聲明對(duì)象變量時(shí)要精確。如果代碼將要運(yùn)行經(jīng)過窗體的文本框控件,聲明對(duì)象變量為文本框,而不要僅僅聲明為控件。這樣,VBA不必確定到底說的是哪種控件。例如:可以用

         Sub CycleControls (cntl as TextBox)


      代替

         Sub CycleControls (cntl as control)


      來節(jié)省運(yùn)行時(shí)間。

5.切換True False

    在把一個(gè)標(biāo)志位從True 翻轉(zhuǎn)到 False 時(shí),沒有必要用一個(gè)IF…Then…Else結(jié)構(gòu)來完成檢查值標(biāo)志的任務(wù)?梢杂NOT操作符把值翻轉(zhuǎn),從而節(jié)省時(shí)間和代碼。通過設(shè)定一個(gè)布爾變量為該變量的非,就可以翻轉(zhuǎn)它。

       可以用

           bFlag=Not bFlag


       代替

           If bFlag=False then


              bFlag=True


           Else


              bFlag=False


           End IF


       運(yùn)行一行代碼比運(yùn)行幾行計(jì)算要節(jié)省許多時(shí)間。

6.用Len()的函數(shù)代替空字符串

    為了測(cè)試一個(gè)字符串變量中是否含有字符,應(yīng)該使用Len函數(shù)而不是把字符串變量和空字符串(”” “”)進(jìn)行比較。用Len計(jì)算比將變量和空字符串進(jìn)行比較更快。

       Sub CheckString (strString as string)


            If Len(strString) then


               MsgBox “Here is the string : “ & strString


           End if


      End Sub


7
.用True False 代替Zero


    因?yàn)?/FONT>True False是二進(jìn)進(jìn)制的,它們比數(shù)字Zero更容易求值?梢韵裣旅孢@樣使用TrueFalse

       Function ShowNumber(dblNumber as Double) as string


           If dblNumber then


             ShowNumber=”The number is “ & dblNumber


         End if


      End Function


8.快速對(duì)象引用

      使用變量而不是重復(fù)的對(duì)象引用。引用一個(gè)在窗體、控件、報(bào)表或查詢中存在的變量比再回頭引用這個(gè)對(duì)象更快。代替再次引用窗體

      Forms![frmMyForm].Height=500

      Forms![frmMyForm].Width=500

      可以嘗試聲明一個(gè)變量并按下面這樣的引用它:

      Dim Frm as Form


      Set Frm =Forms![frmMyForm]

      Frm.Height=500
      Frm.Width=500

    在處理一個(gè)對(duì)象的多個(gè)屬性時(shí),用With…End With來減少對(duì)象的引用。這在路徑和引用很長(zhǎng)時(shí)特別有用,而且也容易錄入

      With Forms![frmMainForm]![txtCustomerName]


         .left=200

         .top=300
         .height=200
         .width=100


       End with


    其中ME代表活動(dòng)窗體,所以它直接指向當(dāng)前窗體,省略了確定變量大小和聲明對(duì)象變量。因?yàn)樗辉?/FONT>CBF中有效,所以不能把它用在一般的標(biāo)模塊中,例如:

      With ME


        .Height=500


        .Width=500


      End With


9.快速數(shù)組使用

      要使用數(shù)組。在一般情況下,數(shù)組駐留在內(nèi)存中,對(duì)其防問和操作都很快。數(shù)組的擴(kuò)大所需的時(shí)間無窮小,并且它們對(duì)內(nèi)存使作效率極高。假如在開發(fā)過程中數(shù)組的大小沒有確定,那么可使用動(dòng)態(tài)數(shù)組。動(dòng)態(tài)數(shù)組在運(yùn)行時(shí)可以根據(jù)需要重新定義維數(shù)。千萬不要聲明一個(gè)浪費(fèi)內(nèi)存的大型靜態(tài)數(shù)組。
    用Erase 關(guān)鍵字可以清空數(shù)組而不破壞它的結(jié)構(gòu)。Erase清空數(shù)組的內(nèi)容,但不完全刪除它。

       Erase myArray

    相反地,需要擴(kuò)大一個(gè)數(shù)組但不破壞它的內(nèi)容時(shí)可以用Redim Preserve

       ReDim Preserve myArray (Ubound(myArray+1))


    數(shù)組存儲(chǔ)的數(shù)據(jù)可以來自已記錄集、控件組,也可以讀自文件、用戶輸入以及任何一致的數(shù)據(jù)。例如,與其保持DAO記錄集打開而招致相關(guān)的開銷,不如打開數(shù)組后用GetRow()方法來產(chǎn)生一個(gè)合適的專用數(shù)組,然后釋放記錄集,這樣可以節(jié)省內(nèi)存并緩解多用戶情況下的沖突。GetRow()帶有一個(gè)參數(shù):需要裝載到數(shù)組中的記錄行數(shù)。

        Dim db as Database

        Dim RowArray as Variant
        Dim rs as Recordset

        Set db=CurrentDb()

        Set rs=db.opentrecordset(“Quarterly Orders”)
        RowArray=rs.GetRows(rs.Recordcount)
        Rs.close
         …
       在數(shù)組裝載以后就可以對(duì)其中的數(shù)據(jù)根據(jù)情形進(jìn)行操作或者把記錄裝載到一個(gè)非綁定的窗體中。

10.盡可能使用常數(shù)

    為了讓VBA取回一個(gè)變量的當(dāng)前值,該變量必須是沒有被引用的,這個(gè)過程每次都需要幾個(gè)CPU指令;如果該變量沒有在處理器的寄存器或緩存中,需要的指令更多。相反,常數(shù)只需很少的幾條指令,而且還有益于增加代碼的可讀性。例如,可以創(chuàng)建一個(gè)符號(hào)常量,代替在代碼中從頭到尾使用42,比方說

       TheAnswerToLifeTheUniverseAndEverything
并把它設(shè)定為42。VBA讀取常量比變量更快。況且,其它的開發(fā)者使用常量也比42這個(gè)鬼數(shù)更容易。

11.書簽的合理使用

      書簽是可以在用戶界面里許多記錄中瀏覽移動(dòng)時(shí)使用的簡(jiǎn)便方法,但它們也是有害卻引人上癮的。說它們簡(jiǎn)便是因?yàn)樗鼈兯俣瓤,?duì)代碼微不足道。說它們有害是因?yàn)樗鼈冎淮硪粋(gè)記錄在一系列行中的臨時(shí)位置。
    要記住有兩種書簽:一種用于窗體,一種用于記錄集。窗體書簽是一個(gè)動(dòng)態(tài)分配給底層記錄集副本的變體數(shù)組。DAO書簽是在字節(jié)數(shù)組中指向記錄集中每一個(gè)記錄的條目。但無論哪種書簽都是隨著記錄集及其副本而不停地創(chuàng)建、破壞、重建。它們并不代表記錄,與主鍵也沒有任何關(guān)系。數(shù)據(jù)操作應(yīng)該使用那些與關(guān)系數(shù)據(jù)庫理論和設(shè)計(jì)相關(guān)一致的技術(shù),而不是那些記錄集中的記錄的偶然位置。

12.關(guān)閉與銷毀

    快速的代碼是整齊嚴(yán)謹(jǐn)?shù)拇a。在完成任務(wù)時(shí)要關(guān)閉記錄集,在對(duì)象不再使用時(shí)要把它們?cè)O(shè)定為Nothing。不用的窗體要關(guān)閉,不用的數(shù)據(jù)庫連接也要關(guān)閉。保存變量的局域化,這樣在控制轉(zhuǎn)換到另一個(gè)函數(shù)時(shí)它們會(huì)因超出有效范圍而自動(dòng)消失。寧可使用動(dòng)態(tài)數(shù)組也不用靜態(tài)數(shù)組。總之,要盡一切努力來消化Access應(yīng)用可能消耗的資源。

       Rs.close

       Set db=Nothing

13.用SQL代替DAO

   只有在別無選擇時(shí)才在整個(gè)記錄集中循環(huán)操作。優(yōu)化Jet數(shù)據(jù)庫以使用SQL來操作數(shù)據(jù)和數(shù)據(jù)結(jié)構(gòu)。只要可能,就使用查詢而不是DAO,很少有DAO比精心創(chuàng)建的查詢速度快的情況。查詢有執(zhí)行規(guī)劃而且可以利用索引,但DAO卻不能。
    如果必須用一個(gè)對(duì)象模型來選定數(shù)據(jù),應(yīng)該用ADO而不是DAOADO是通過對(duì)象模塊來完成選定數(shù)據(jù)操作或數(shù)據(jù)定義的首選標(biāo)準(zhǔn)。DAO是凝固不變的,而且沒有進(jìn)一步的擴(kuò)展和提高。

14.使用集合的索引數(shù)

      在使用對(duì)象集合時(shí),盡可能使用它們的索引數(shù)。索引數(shù)是集合的內(nèi)部識(shí)別標(biāo)記,它們比集合對(duì)象的其他屬性(如名稱)用起來更快。例如,下面的兩個(gè)語句顯示了引用當(dāng)前數(shù)據(jù)庫的兩種不同方法。對(duì)Currentdb()的引用會(huì)自動(dòng)刷新數(shù)據(jù)庫的集合從而消耗時(shí)間,但第一個(gè)引用則不會(huì)。

        Set db=DBEngine(0)(0)


      比

        Set db=Currentdb()


      更快。類似地,語句

        Set cntl=Forms!frmMyForm(0)


      比

        Set contl=Forms![frmMyForm]![myControl]

      更快。

      使用集合成員的索引數(shù)在循環(huán)中尤其有用,這將在下面討論。

15.加快循環(huán)速度

    當(dāng)循環(huán)經(jīng)過一個(gè)集合時(shí),使用For…Each 而不是For…Next。多考慮一下窗體的控件,是這些控件組成了集合。使用下面的語法來使循環(huán)通過每一個(gè)控件:

      For Each cntl on frm


           ….


      Next


    要比使用一個(gè)簡(jiǎn)單的For…Next循環(huán)運(yùn)行快。For…Next循環(huán)需要重復(fù)對(duì)象引用,但是For…Each 循環(huán)不需要。
如果需要使用循環(huán)通過對(duì)象集合,開發(fā)者肯定希望避免對(duì)集合的不必要刷新。即使在一個(gè)小的數(shù)據(jù)庫中,刷新集合也會(huì)破壞應(yīng)用的性能。在使用For …Next循環(huán)時(shí)不必在下一行重復(fù)變量,所以可以節(jié)省時(shí)間。

      For i=1 to 100


          …….do what you want


      Next


    這樣做的好處在嵌套循環(huán)中特別顯著。另外,也不要重復(fù)計(jì)算For 所在行的上下限。上限應(yīng)該在進(jìn)入循環(huán)之前就建立好。下面的第一個(gè)代碼段計(jì)算循環(huán)退出標(biāo)準(zhǔn)reccount一次。第二個(gè)代碼段則在每一步循環(huán)中都計(jì)算一次。顯然,第一個(gè)代碼段是更快的代碼。

       Reccount=rs.recordcount/2


        For i=1 to recount

          …
        Next

       For i=1 to rs.recordcount/2

          …..


       Next


16.杜絕在代碼中使用IIF()

      不要在代碼中使用IIF() 函數(shù)。這個(gè)函數(shù)在產(chǎn)生結(jié)果之前必須計(jì)算包含其中的所有表達(dá)式。標(biāo)準(zhǔn)的IF…Then..Else結(jié)構(gòu)速度更快。

17.合理安排Select Case

    在使用Select Case結(jié)構(gòu)時(shí),結(jié)構(gòu)安排上要把經(jīng)常遇到的情況放在頂端,因?yàn)樵谕ㄟ^情況選項(xiàng)時(shí)要依次對(duì)每一種情況進(jìn)行嘗試,安排它們時(shí)把最常發(fā)生的放在前面可以使執(zhí)行盡早退出這個(gè)選擇結(jié)構(gòu)。

18.使用.Excute,棄用RunSQL

      任何時(shí)候都要避免基于Docmd的代碼,DocmdVBA最高級(jí)別的代碼,是從Access沒有采用VBA而只是簡(jiǎn)單的宏來完成自動(dòng)操作的版本中繼承來的。如果還有其他的選擇,請(qǐng)接受吧。

        Docmd.RunSql “….”


     比

        Querydef.Excute


     運(yùn)行速度慢。

發(fā)表評(píng)論 評(píng)論 (2 個(gè)評(píng)論)

回復(fù) zbjit 2007-9-12 13:30
受益匪淺,謝謝。
回復(fù) rcylbx 2009-2-10 15:13
這篇文章應(yīng)該經(jīng)?纯

facelist doodle 涂鴉板

您需要登錄后才可以評(píng)論 登錄 | 注冊(cè)

QQ|站長(zhǎng)郵箱|小黑屋|手機(jī)版|Office中國(guó)/Access中國(guó) ( 粵ICP備10043721號(hào)-1 )  

GMT+8, 2024-10-23 10:31 , Processed in 0.054740 second(s), 15 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.