代码之家  ›  专栏  ›  技术社区  ›  PoojaP

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

  •  0
  • PoojaP  · 技术社区  · 6 年前

    我有一个excel电子表格,有大约300000条记录。我在第一行应用Vlookup公式,然后尝试将特殊as公式复制并粘贴到其余行。但是,计算往往会耗费大量时间,并显示多线程的进度,这非常缓慢。

    有没有人能提出一种方法来节省时间。

    非常感谢。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Charles Williams    6 年前

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

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

        2
  •  0
  •   SpaghettiCode    6 年前

    如果你被它困住了,最好的办法就是通过避免常见的陷阱来优化你的公式。您提到您正在使用 VLOOKUP ,为什么不试试 INDEX/MATCH combo,它更通用,速度比 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