[英]Excel vba custom lookup function: fast when used manually, slow in macros
[英]Difference in function performance between calling manually ('=') or through macros
我写了一个查找功能。 它的性能差异很大,这取决于我是手动在工作表本身上(通过'=')还是通过宏对其进行调用。
我的宏执行以下操作:
Function betterSearch(searchCell As Range, aCol As Range, bCol As Range)
For Each cell In aCol
If LCase(cell.Value) = LCase(searchCell.Value) Then
betterSearch = bCol.Cells(cell.row, 1)
Exit For
End If
betterSearch = "Not found"
Next
End Function
宏将打开resultsWorkbook和dataWorkbook,然后从dataWorkbook的resultWorkbook中搜索A列中的四个值,并从dataWorkbook的其他其他列返回相应的数据。
'...opening resultWorkbook and dataWorkbook
For aRow = 6 To 9
resultWorkbook.Worksheets("B3").Cells(aRow, 125).Value = _
betterSearch(resultWorkbook.Worksheets("B3").Cells(aRow, 1) _
, dataWorkbook.Worksheets("page 1").Range("A:A") _
, dataWorkbook.Worksheets("page 1").Range("Z:Z"))
resultWorkbook.Worksheets("B3").Cells(aRow, 126).Value = _
betterSearch(resultWorkbook.Worksheets("B3").Cells(aRow, 1) _
, dataWorkbook.Worksheets("page 1").Range("A:A") _
, dataWorkbook.Worksheets("page 1").Range("I:I"))
Next aRow
这确实很慢-1 分钟需要几分钟 。 但是,当我手动打开该文件并键入公式并按Enter时,它会立即进行计算(因此,我的函数不需要优化-它已经可以快速地进行计算,而只是在工作表中,而不是在宏内部)。
我不是要优化功能。 我想了解 为什么会出现这种性能差异。 对于主应用程序和不可见的应用程序,我都有Application.Calculation = xlCalculationManual
,它可以运行并完成所有工作: ExcelApp.Calculation = xlCalculationManual
,似乎正在将工作簿的状态更改为手动,但是性能很慢,好像工作簿仍然是自动的。
您可以使用“ Find
功能,并使用MatchCase:=False
因此将不区分大小写。
这比遍历您的专栏要快得多。
码
Function betterSearch(searchCell As Range, aCol As Range, bCol As Range) As String
Dim FndRng As Range
Set FndRng = aCol.Find(what:=LCase(searchCell.Value), LookIn:=xlValues, lookat:=xlWhole, _
searchorder:=xlRows, searchdirection:=xlNext, MatchCase:=False)
If Not FndRng Is Nothing Then ' Find was successful
betterSearch = bCol.Cells(FndRng.Row, 1)
Else
betterSearch = "Not found"
End If
End Function
可能与使用整个列范围有关。
我认为,当从宏调用函数时,您将强制Excel将每个完整列引用的百万个值传输到VBA(将数据从Excel传输到VBA非常慢)。
从工作表中调用函数时,您只传输一个范围对象,然后逐个单元地循环,因此传输到VBA的数据量可能少几十万倍(取决于查找范围的下限)一场比赛)。
尝试在宏中为完整的列引用设置范围变量,然后将范围变量而不是Range(I:I)传递给BetterSearch
原因是因为您在宏中某个区域的单元格之间循环。 与数组相比,这非常慢。 每个cell.value调用都在变慢。 在Excel本身中,此减慢幅度不大,因为Range对象是应用程序本身的对象。
一次将所有需要的数据从应用程序传递到VBA的速度要比多次仅传递很少的数据要慢。
如果您重写您的代码位,它将与您调用它的位置快速相关。
首先将searchValue存储在变量中。 因此,您无需为每个调用评估公式。 在您的代码中,每次比较都会对搜索值进行评估,但这没有意义,因为它不会改变。
其次,将aCol Range的值存储在变量数组中。 对于整个专栏来说,这样做非常快。 之后,您可以真正快速地比较列中的每个单个值(比Find / Match / Variant-Array的Find或Match函数性能比较快)
这是您更改的代码
Function betterSearch(searchCell As Range, aCol As Range, bCol As Range)
Dim searchVal as String
Dim colVals() as Variant
Dim r as Long
searchVal = LCase(searchCell.Value)
colVals = aCol.Value ' Read data of whole column only once
For r = 1 to Ubound(colVals,1)
If LCase(colVals(r,1)) = searchVal Then
betterSearch = bCol.Cells(r, 1)
Exit For
End If
betterSearch = "Not found"
Next
End Function
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.