【发布时间】:2017-02-07 04:37:14
【问题描述】:
我在 Excel 中创建了一个 VBA 宏,用于查找所有工作表中特定函数的所有实例。我已经能够成功地创建它,但我正在尝试看看在性能方面最好的方法是什么,因为我正在搜索的功能可能会在大型工作簿中使用大量时间。
我使用了两种方法。
方法 1 - 遍历每个单独的单元格并使用“instr”函数查看单元格公式是否包含该函数。
方法 2 - 使用 Find 和 FindNext 方法以及 do 循环来仅循环遍历实际具有函数的单元格。
我惊讶地发现,当函数很多时,方法 1 快很多(当函数非常少时,方法 2 运行得更快)。
谁能解释一下这是怎么回事?
这是一个带有我的代码示例的示例。
在“Sheet1”上,我在单元格 A1:J5000 中放置了一个名为“MyFunction”的用户定义函数。然后在单元格 A5001:J10000 中,我将它们留空,但将它们着色为黄色以强制使用的范围为 A1:J10000。
尽管方法 1 循环遍历每 100,000 个单元格,但它比仅循环遍历找到的 50,000 个单元格的方法 2 快得多
方法 1 的平均运行时间约为 171 毫秒,方法 2 的平均运行时间约为 1,531 毫秒。
方法一和方法二的代码示例:
方法一
Private Sub TestMethod1()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Dim MySheet As Worksheet, MyRange As Range, MyCell As Range
Dim MyCellAddress As String, MyCellFormula As String, MyFunction As String
Dim CountTotalCells As Long, CountTotalFunctions As Long
Dim sw, swEndTime As Long
Set sw = New StopWatch
sw.StartTimer
MyFunction = "=MyFunction("
CountTotalCells = 0
CountTotalFunctions = 0
Set MySheet = Sheets("Forum Question")
Set MyRange = MySheet.UsedRange
For Each MyCell In MyRange
MyCellFormula = MyCell.Formula
CountTotalCells = CountTotalCells + 1
If InStr(1, MyCellFormula, MyFunction) > 0 Then
CountTotalFunctions = CountTotalFunctions + 1
End If
Next
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
swEndTime = sw.EndTimer
MsgBox CountTotalCells & ", " & CountTotalFunctions & ", " & swEndTime & " ms"
End Sub
方法二
Private Sub TestMethod2()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Dim MySheet As Worksheet, MyRange As Range, MyCell As Range
Dim MyCellAddress As String, MyCellFormula As String, MyFunction As String, MyCellFirst As String
Dim CountTotalCells As Long, CountTotalFunctions As Long
Dim sw, swEndTime As Long
Set sw = New StopWatch
sw.StartTimer
MyFunction = "=MyFunction("
CountTotalCells = 0
CountTotalFunctions = 0
Set MySheet = Sheets("Forum Question")
Set MyRange = MySheet.UsedRange
Set MyCell = MyRange.Cells.Find( _
What:=MyFunction, _
After:=[A1], _
LookIn:=xlFormulas, _
LookAt:=xlPart, _
SearchOrder:=xlRows, _
SearchDirection:=xlNext, _
MatchCase:=True _
)
If Not MyCell Is Nothing Then
MyCellFirst = MyCell.Address
Do
Set MyCell = MyRange.FindNext(After:=MyCell)
MyCellAddress = MyCell.Address
MyCellFormula = "z" & MyCell.Formula
CountTotalCells = CountTotalCells + 1
If InStr(1, MyCellFormula, MyFunction) > 0 Then
CountTotalFunctions = CountTotalFunctions + 1
End If
If MyCell Is Nothing Or MyCellAddress = MyCellFirst Then
Exit Do
End If
Loop
End If
Set MyCell = Nothing
swEndTime = sw.EndTimer
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
MsgBox CountTotalCells & ", " & CountTotalFunctions & ", " & swEndTime & " ms"
End Sub
【问题讨论】:
-
这个帖子不是更适合StackExchange吗?