巨大的spreadhseet - 公式的计算速度慢

时间:2018-05-04 13:19:17

标签: excel excel-formula

我有一张包含约300,000条记录的Excel电子表格。我在第一行应用Vlookup公式,然后尝试将特殊的公式复制并粘贴到剩余的行中。但是,计算往往会耗费大量时间,并显示多线程的进度,这实际上很慢。

有人可以建议一种方法来节省时间。

谢谢!

2 个答案:

答案 0 :(得分:1)

假设您需要进行完全匹配查找,那么最快的公式方法是对数据进行排序,然后使用双重VLOOKUP技巧。

有关详细信息,请参阅我的博文: https://fastexcel.wordpress.com/2012/03/29/vlookup-tricks-why-2-vlookups-are-better-than-1-vlookup/

答案 1 :(得分:0)

如果你坚持下去,最好的办法是通过避免常见的陷阱来优化你的公式。您已经提到过您正在使用VLOOKUP,为什么不尝试INDEX/MATCH组合,它更通用,速度更快VLOOKUP。其他优化技术包括:

  • 避免挥发性公式
  • 使用帮助列
  • 以这样的方式排列列,使得计算顺序从左到右,从上到下,非常类似于阅读英文文本
  • 使用结构化和命名参考
  • 启用手动计算,以便每次进行最轻微的更改时都不会重新计算公式

您可能还想使用计时器来衡量Excel计算时间,以便比较您的不同方法,例如Charles Williams撰写的这篇文章,来自Microsoft Developer Network的一篇文章。将此代码粘贴到VBA编辑器中:

#If VBA7 Then
    Private Declare PtrSafe Function getFrequency Lib "kernel32" Alias _
        "QueryPerformanceFrequency" (cyFrequency As Currency) As Long
    Private Declare PtrSafe Function getTickCount Lib "kernel32" Alias _
         "QueryPerformanceCounter" (cyTickCount As Currency) As Long
#Else
    Private Declare Function getFrequency Lib "kernel32" Alias _                                            "QueryPerformanceFrequency" (cyFrequency As Currency) As Long
    Private Declare Function getTickCount Lib "kernel32" Alias _
        "QueryPerformanceCounter" (cyTickCount As Currency) As Long
#End If
Function MicroTimer() As Double
'

' Returns seconds.
    Dim cyTicks1 As Currency
    Static cyFrequency As Currency
    '
    MicroTimer = 0

' Get frequency.
    If cyFrequency = 0 Then getFrequency cyFrequency

' Get ticks.
    getTickCount cyTicks1                            

' Seconds
    If cyFrequency Then MicroTimer = cyTicks1 / cyFrequency 
End Function

Sub RangeTimer()
    DoCalcTimer 1
End Sub
Sub SheetTimer()
    DoCalcTimer 2
End Sub
Sub RecalcTimer()
    DoCalcTimer 3
End Sub
Sub FullcalcTimer()
    DoCalcTimer 4
End Sub

Sub DoCalcTimer(jMethod As Long)
    Dim dTime As Double
    Dim dOvhd As Double
    Dim oRng As Range
    Dim oCell As Range
    Dim oArrRange As Range
    Dim sCalcType As String
    Dim lCalcSave As Long
    Dim bIterSave As Boolean
    '
    On Error GoTo Errhandl

' Initialize
    dTime = MicroTimer              

    ' Save calculation settings.
    lCalcSave = Application.Calculation
    bIterSave = Application.Iteration
    If Application.Calculation <> xlCalculationManual Then
        Application.Calculation = xlCalculationManual
    End If
    Select Case jMethod
    Case 1

        ' Switch off iteration.

        If Application.Iteration <> False Then
            Application.Iteration = False
        End if

        ' Max is used range.

        If Selection.Count > 1000 Then
            Set oRng = Intersect(Selection, Selection.Parent.UsedRange)
        Else
            Set oRng = Selection
        End If

        ' Include array cells outside selection.

        For Each oCell In oRng
            If oCell.HasArray Then
                If oArrRange Is Nothing Then 
                    Set oArrRange = oCell.CurrentArray
                End If
                If Intersect(oCell, oArrRange) Is Nothing Then
                    Set oArrRange = oCell.CurrentArray
                    Set oRng = Union(oRng, oArrRange)
                End If
            End If
        Next oCell

        sCalcType = "Calculate " & CStr(oRng.Count) & _
            " Cell(s) in Selected Range: "
    Case 2
        sCalcType = "Recalculate Sheet " & ActiveSheet.Name & ": "
    Case 3
        sCalcType = "Recalculate open workbooks: "
    Case 4
        sCalcType = "Full Calculate open workbooks: "
    End Select

' Get start time.
    dTime = MicroTimer
    Select Case jMethod
    Case 1
        If Val(Application.Version) >= 12 Then
            oRng.CalculateRowMajorOrder
        Else
            oRng.Calculate
        End If
    Case 2
        ActiveSheet.Calculate
    Case 3
        Application.Calculate
    Case 4
        Application.CalculateFull
    End Select

' Calculate duration.
    dTime = MicroTimer - dTime
    On Error GoTo 0

    dTime = Round(dTime, 5)
    MsgBox sCalcType & " " & CStr(dTime) & " Seconds", _
        vbOKOnly + vbInformation, "CalcTimer"

Finish:

    ' Restore calculation settings.
    If Application.Calculation <> lCalcSave Then
         Application.Calculation = lCalcSave
    End If
    If Application.Iteration <> bIterSave Then
         Application.Iteration = bIterSave
    End If
    Exit Sub
Errhandl:
    On Error GoTo 0
    MsgBox "Unable to Calculate " & sCalcType, _
        vbOKOnly + vbCritical, "CalcTimer"
    GoTo Finish
End Sub

您还可以查看“参考”下的链接,了解有关优化Excel性能的更多建议和技巧。虽然在第二个链接中,它说:

“使用Excel公式计算和工作表函数通常比使用VBA用户定义函数更快。” 2

虽然如果我们谈论计算过程本身但如果你在VBA中进行计算,这可能是真的,你的输出将是静态的。因此,如果您正在使用财务建模,假设情景等等,如果启用自动计算,则等待每分钟更改15分钟会很痛苦,因为公式正在主动引用单元格,监视任何变化。

希望这会有所帮助..

参考文献:

Excel performance: Improving calculation performance

Excel performance: Tips for optimizing performance obstructions

Excel performance: Performance and limit improvements