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

时间:2017-07-05 08:35:48

标签: excel vba performance excel-formula

我写了一个查找函数。它的性能差别很大显着,这取决于我是否在工作表本身(通过'=')或通过手动调用它。

我的宏执行以下操作:

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它似乎正在将工作簿的状态更改为手动但速度缓慢就好了工作簿仍然是自动的。

3 个答案:

答案 0 :(得分:1)

您可以使用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

答案 1 :(得分:1)

可能与使用整个列范围有关。
我认为从宏调用函数时,您强制Excel为每个完整列引用将一百万个值传输到VBA(将数据从Excel传输到VBA非常慢)。
当从工作表中调用函数时,您只传输一个范围对象,然后逐个循环,因此传输到VBA的数据量可能减少数十万倍(取决于您有多远的范围)去找比赛。)

尝试在宏中为整个列引用设置范围变量,然后将范围变量而不是Range(I:I)传递给BetterSearch

答案 2 :(得分:0)

原因是,因为您在宏中某个区域的单元格之间循环。与数组相比,这非常慢。 每个cell.value调用都在变慢。在Excel本身中,此减慢幅度不大,因为Range对象是应用程序本身的对象。

一次将所有需要的数据从应用程序传递到VBA的速度要比多次只传递很少的数据要慢。

如果您重写代码位,它将很快与您调用的位置无关。

首先将searchValue存储在变量中。因此,您无需为每个调用评估公式。在您的代码中,每次比较都会评估搜索值,但这没有意义,因为它不会改变。

第二个将aCol Range的值存储在一个变量数组中。对于整个专栏来说,这样做非常快。之后,您可以真正快速地比较列中的每个值(比查找或匹配功能Performance comparison of Find / Match / Variant-Array更快)

这是您更改的代码

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