繁体   English   中英

手动调用('=')或通过宏调用之间的函数性能差异

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM