2018年10月1日 星期一

10個加速Excel巨集的方法

用VBA將報表自動化也一段時間了,

但有時候資料量過大,VBA的效能真的會讓人覺得......

不過看到這個國外網站後真的獲益良多~


Ref:
"10 ways to speed up your macros"
https://www.dummies.com/software/microsoft-office/excel/10-ways-to-speed-up-your-macros/

基本上1 ~ 5點可以放在一起:

1. HALTING SHEET CALCULATIONS (停止sheet頁面的自動計算)

→  
當調整為手動時(Application.Calculation = xlCalculationManual),執行巨集時,sheet上所帶的公式都不會跟著更新。因此如果執行巨集時會用到公式,此功能依然要設為自動(Application.Calculation = xlCalculationAutomatic)

2. DISABLING SHEET SCREEN UPDATING (停止螢幕更新)

→   此為「開啟」螢幕更新的狀態

  此為「關閉」螢幕更新的狀態

當自動生成的Sheet很多時,速度是不是有差呢!! 小弟覺得最有感的加速方式!!

範例檔案:網頁爬蟲(環境資源資料開放平臺)

3. TURNING OFF STATUS BAR UPDATES (停止狀態列更新)

→ 狀態列在哪邊?就是sheet下面那條


4. TELLING EXCEL TO IGNORE EVENTS (忽略事件變更)

→ 可參照 https://ithelp.ithome.com.tw/articles/10156956 (Excel VBA 的眉眉角角Day6:關於工作表程式觸發與暫停觸發)

5.  HIDING PAGE BREAKS (隱藏分頁線)

→ 列印時,分隔第1頁、第2頁、...的線,這個平常基本上不會用到

根據上述5點,可依序加入在VBA code的最上方 與 最下方
最上方:關掉、變更1~5點所提及的應用程式物件狀態
最下方:開啟、變更1~5點所提及的應用程式物件狀態
Sub SpeedUp_Macro()
    Application.Calculation = xlCalculationManual       '---1
    Application.ScreenUpdating = False                  '---2
    Application.DisplayStatusBar = False                '---3
    Application.EnableEvents = False                    '---4
    ActiveSheet.DisplayPageBreaks = False               '---5
    
    'Put your VBA code here
    
    Application.Calculation = xlCalculationAutomatic    '---1
    Application.ScreenUpdating = True                   '---2
    Application.DisplayStatusBar = True                 '---3
    Application.EnableEvents = True                     '---4
    ActiveSheet.DisplayPageBreaks = True                '---5
End Sub

6.   SUSPENDING PIVOT TABLE UPDATES (停止樞紐分析表更新)

這邊應該滿直觀的,當要執行你的Code之前,先將樞紐分析表切換成「手動更新 」,
等到Code執行完後再切回「自動更新」。

Sub Macro1()
    ActiveSheet.PivotTables("PivotTable1").ManualUpdate = True
    'Put your VBA code here
    ActiveSheet.PivotTables("PivotTable1").ManualUpdate = False
End Sub


7. STEERING CLEAR OF COPY AND PASTE (避開"複製"與"貼上"的指令) 

一般來講,我們用巨集錄製的複製與貼上指令會長這樣:
'Ver. 1
Range("A1").Select
Selection.Copy
Range("B1").Select
ActiveSheet.Paste
但實際上,複製與貼上的指令可用一行完成,並且可省下上述Code複製後暫存於剪貼簿的時間
'Ver. 2
Range("A1").Copy Destination:=Range("B1")
小弟針對此寫了一小段測試Code:VBA-複製貼上語法比較







現在給定1~10000這一萬個數字,我利用這兩種版本的程式碼,

分別執行100次,最後記錄這100次它們各別平均花了多少時間

Ver. 1 的程式碼:平均約0.05 sec ;Ver. 2的程式碼:平均約0.01 sec

當資料大時,Ver. 2的速度明顯優於 Ver. 1

此外,還有提到另外兩項:
(1) 純粹複製數值
Range("B1").Value = Range("A1").Value
(2) 複製公式
Range("B1").Formula= Range("A1").Formula
8. USING THE WITH STATEMENT (使用With敘述)

直接使用With敘述,可讓excel知道你With了哪一個Object,

然後就可以一次修改Object內部成員的值。

9. AVOIDING THE SELECT METHOD (避免使用"Select")

呼應第7點,複製貼上用一行解決即可,避免使用多餘的Select指令

10. LIMITING TRIPS TO THE WORKSHEET (限制程式在Worksheet中的行為)

這點真的太實際啦!
若在程式碼中,若一直針對Cells操作,將使得程式效率大幅降低。
原文的範例,即是將Range("A1")的值先設給一個變數,
然後再用此變數去跑For loop判斷式,藉此避免每次跑For loop時,都要去存取Cells

此外,可以再參照此網站的第6點,馬上開門見山說了:
「每一次Excel 與 VBA 之間的資料搬移都是額外的負荷」
這邊我覺得他講得很好,那張圖更是貼切XD

而且第6點這個Range 轉成 Array的方法可以說是相當實用!!

沒有留言:

張貼留言