2009-11-17 77 views
2

我爲一個名爲Terminal的實體創建了一個類模塊。我有一種方法通過瀏覽175個單獨的工作表並從特定單元格中提取正確的數據來填充此類。這個過程非常快(大約2秒),但是當我嘗試將這些數據寫回新工作表時,它需要更長的時間(45秒)。看起來這個過程應該像填充類一樣快,因爲它永遠不必離開工作表,但事實並非如此。下面是我用來將數據寫入工作表的過程,我忽略了導致它運行得如此緩慢的原因嗎?通過Excel中的類迭代VBA

Application.ScreenUpdating = False 
Dim rowNumber As Integer 
Dim colNumber As Integer 
Dim terminalCode As String 
Dim terminal As clsTerminal 

rowNumber = 7 
colNumber = 1 

For Each terminal In terminals 

     'Add hyperlink to each terminal code 
     Sheets("Terminal Summary").Hyperlinks.Add Anchor:=Cells(rowNumber, colNumber), Address:="", _ 
      SubAddress:=terminal.terminalCode + "!A1", TextToDisplay:=terminal.terminalCode 

     Sheets("Terminal Summary").Cells(rowNumber, colNumber + 1).Value = "Current" 

     'Current period 
     Sheets("Terminal Summary").Cells(rowNumber, colNumber + 2).Value = terminal.iBShipments 
     Sheets("Terminal Summary").Cells(rowNumber, colNumber + 3).Value = terminal.oBShipments 
     Sheets("Terminal Summary").Cells(rowNumber, colNumber + 4).Value = terminal.iBNetRevenue 
     Sheets("Terminal Summary").Cells(rowNumber, colNumber + 5).Value = terminal.oBNetRevenue 
     Sheets("Terminal Summary").Cells(rowNumber, colNumber + 6).Value = terminal.iBWeight 
     Sheets("Terminal Summary").Cells(rowNumber, colNumber + 7).Value = terminal.oBWeight 
     Sheets("Terminal Summary").Cells(rowNumber, colNumber + 8).Value = terminal.iBMileage 
     Sheets("Terminal Summary").Cells(rowNumber, colNumber + 9).Value = terminal.oBMileage 
     Sheets("Terminal Summary").Cells(rowNumber, colNumber + 10).FormulaR1C1 = "=IFERROR(RC[-4]/RC[-8],0)" 
     Sheets("Terminal Summary").Cells(rowNumber, colNumber + 11).FormulaR1C1 = "=IFERROR(RC[-4]/RC[-8],0)" 
     Sheets("Terminal Summary").Cells(rowNumber, colNumber + 12).FormulaR1C1 = "=IFERROR(RC[-8]/RC[-10],0)" 
     Sheets("Terminal Summary").Cells(rowNumber, colNumber + 13).FormulaR1C1 = "=IFERROR(RC[-8]/RC[-10],0)" 
     Sheets("Terminal Summary").Cells(rowNumber, colNumber + 14).FormulaR1C1 = "=IFERROR(RC[-10]/(RC[-8]/100),0)" 
     Sheets("Terminal Summary").Cells(rowNumber, colNumber + 15).FormulaR1C1 = "=IFERROR(RC[-10]/(RC[-8]/100),0)" 
     Sheets("Terminal Summary").Cells(rowNumber, colNumber + 16).FormulaR1C1 = "=IFERROR(RC[-12]/RC[-8],0)" 
     Sheets("Terminal Summary").Cells(rowNumber, colNumber + 17).FormulaR1C1 = "=IFERROR(RC[-12]/RC[-8],0)" 

     rowNumber = rowNumber + 1 
    Next terminal 

編輯 我應該注意的終端是終端類的集合

回答

4

這種類型的代碼,一個常見的錯誤是,每當你將數據寫入到電子表格時,Excel運行通過計算(它會評估工作簿中的所有公式,以確定是否需要使用新數據計算它們)。

如果你的循環前禁用自動計算,然後以後重新啓用它,事情就會快得多移動:

Application.Calculation = xlCalculationManual 
For Each terminal In terminals 
... 
Next terminal 
Application.Calculation = xlCalculationAutomatic 
+0

死的。性能提高95.5%。謝謝 – 2009-11-17 15:38:51

+0

不客氣:) – 2009-11-17 15:39:18

3

您已經有了很大的儲蓄(關閉自動計算,同時寫),但有是未來的一些其他小技巧。

首先,每次從VBA寫入單元時,都會由於VBA進入工作簿/表單/單元地址並執行寫入而導致開銷。在一次通話中寫入很多單元只會導致一次開銷。因此,將多個值包裝到一個數組中,並將該數組寫入多個單元格會增加時間。幾條線不值得,但是值得數百的努力。

此外,每個「點」還有一點點開銷。 「點」表達式中的術語(如Sheets("Terminal Summary").Cells(rowNumber, colNumber + 2))需要Excel/VBA來確定每個調用中涉及哪些對象。在某些情況下(特別是在引用遠程對象時)開銷可能很大。 VB爲我們提供了With...End With構造,以減少需要繼續解析這些引用:以點開頭的每個表達式自動引用下一個最外面的With中的對象。

所以我們可以得到這樣的:

With Sheets("Terminal Summary") 
    .Cells(rowNumber, colNumber + 2).Resize(1, 8) = terminal.InfoArray 
    .Cells(rowNumber, colNumber + 10).FormulaR1C1 = "=IFERROR(RC[-4]/RC[-8],0)" 
    .Cells(rowNumber, colNumber + 11).FormulaR1C1 = "=IFERROR(RC[-4]/RC[-8],0)" 
    .Cells(rowNumber, colNumber + 12).FormulaR1C1 = "=IFERROR(RC[-8]/RC[-10],0)" 
    .Cells(rowNumber, colNumber + 13).FormulaR1C1 = "=IFERROR(RC[-8]/RC[-10],0)" 
    .Cells(rowNumber, colNumber + 14).FormulaR1C1 = "=IFERROR(RC[-10]/(RC[-8]/100),0)" 
    .Cells(rowNumber, colNumber + 15).FormulaR1C1 = "=IFERROR(RC[-10]/(RC[-8]/100),0)" 
    .Cells(rowNumber, colNumber + 16).FormulaR1C1 = "=IFERROR(RC[-12]/RC[-8],0)" 
    .Cells(rowNumber, colNumber + 17).FormulaR1C1 = "=IFERROR(RC[-12]/RC[-8],0)" 
End With 

我掖陣列東西進入終端類,像這樣:

Public Property Get InfoArray() As Variant 
    InfoArray = Array(iBShipments, oBShipments, iBNetRevenue, oBNetRevenue, iBWeight, oBWeight, iBMileage, oBMileage) 
End Property 

的公式可能會輸出更高效地終端信息全部完成後,每列寫入一次。

有些事情要考慮,至少...

+0

+1這些都是很棒的提示,除了代碼非常乾淨以外,性能還是很棒的。我是一個在VBA中進行攻擊的C#人,看起來我仍然有很多要學習 – 2009-11-17 16:34:14

+0

+1,並且非常感謝。我不知道你可以一次寫完整塊細胞。這將派上用場。 – 2009-11-18 06:56:07

1

你已經有90%的答案,我會給的,但這裏有一個進一步的性能提示。而不是做:

Sheets("Terminal Summary").Cells(rowNumber, colNumber + 10).FormulaR1C1 = "=IFERROR(RC[-4]/RC[-8],0)" 

你可以使用的事實,你在一個語句中給相同的公式列中的所有單元格,並做到這一點:

Sheets("Terminal Summary").Cells(7, 11).Resize(terminals.Count, 1).FormulaR1C1 = "=IFERROR(RC[-4]/RC[-8],0)" 
+0

這使我想到了最後一個問題,比如將一列中的所有公式(或格式)一次性添加到一列中,而不是每次通過列時,添加其他數據的行 – 2009-11-17 21:16:04

+0

是的。如果你可以在VBA中交易做東西來讓Excel自己做,那麼你會看到巨大的速度提升。所以雖然對列的單個賦值可能比對一個單元的單賦值花費更長的時間,但它將比對100個單元的單賦值快得多。 – 2009-11-18 08:26:12

+0

...哎呀,我希望我可以編輯該評論。我的意思是,比每個單元100個任務要快得多。 – 2009-11-18 08:27:13