【问题标题】:Nested loops causing Excel crash嵌套循环导致 Excel 崩溃
【发布时间】:2018-09-04 18:59:32
【问题描述】:

我正在尝试运行一个 VBA 宏,它向下迭代大约 67,000 行,每行 100 列。对于这些行中的每个单元格,将值与另一个工作表中具有 87 个条目的列进行比较。运行代码时没有记录错误,但 Excel 每次都会崩溃。奇怪的是代码似乎可以工作。我将其设置为标记找到匹配项的每一行,并且在崩溃之前这样做。我尝试运行它很多次,它在崩溃之前已经运行了 800 到 11,000 行,具体取决于尝试。

我的第一个怀疑是由于计算量导致内存溢出,但我的系统在运行此代码时显示 CPU 利用率为 100%,内存使用率约为 50%:

Sub Verify()

    Dim codes As String
    Dim field As Object

    For i = 2 To Sheets("DSaudit").Rows.Count
        For Each field In Sheets("Dsaudit").Range(Cells(i, 12), Cells(i, 111))
            r = 1
            While r <= 87
                codes = ThisWorkbook.Sheets("287 Denominator CPT").Cells(r, 1).Value
                If field = codes Then
                    Cells(i, 112).Value = "True"
                r = 88
                Else
                    r = r + 1
                End If
            Wend
        Next field
        i = i + 1
    Next i
End Sub

还应该指出,我对 VBA 还是很陌生,所以我很可能犯了某种严重的新手错误。我可以对此代码进行一些更改以避免崩溃,还是应该废弃它并采取更有效的方法?

【问题讨论】:

  • 你想使用数组并循环它。
  • 那是因为您正在进行至少 10 亿次迭代,很可能更多。这需要很长时间
  • ^^ 使用列来指定 last populated row 并将其用作终点,而不是工作表中的总行数。
  • 我愿意展示如何在这种情况下使用数组来加速它,但我需要知道我的问题的答案,您将 100 列与 87 个值进行比较,但只输出一个值.这是否意味着如果在列表中找到特定行中的任何值返回 true,或者如果所有值都在列表中?现在,如果找到一个,则输出变为 True。只是想确保逻辑是我们想要的。
  • 它不是“崩溃”,而是“(不响应)”——因为它正忙于运行您的嵌套循环以完成。让它运行足够长的时间(一周,也许?),它最终会完成。 Protip:永远不要迭代单元格。仅将必要的数据复制到二维变量数组中,然后迭代该数组。

标签: excel vba crash


【解决方案1】:

尽可能迭代变体数组。这限制了 vba 需要访问工作表的次数。

每次戳破 vba 和 Excel 之间的面纱都需要花费时间。这只会刺穿面纱 3 次,而不是 9,031,385,088

Sub Verify()


    With Sheets("DSaudit")

        'Get last row of Data
        Dim lastrow As Long
        lastrow = .Cells(.Rows.Count, 12).End(xlUp).Row 'if column 12 ends before the last row of data change to column that has them all.

        'Load Array with input Values
        Dim rng As Variant
        rng = .Range(.Cells(2, 12), .Cells(lastrow, 111)).Value

        'Create output array
        Dim outpt As Variant
        ReDim outpt(1 To UBound(rng, 1), 1 To 1)

        'Create Match array
        Dim mtch As Variant
        mtch = Worksheets("287 Denominator CPT").Range("A1:A87").Value

        'Loop through first dimension(Row)
        Dim i As Long
        For i = LBound(rng, 1) To UBound(rng, 1)
            'Loop second dimension(Column)
            Dim j As Long
            For j = LBound(rng, 2) To UBound(rng, 2)
                'Loop Match array
                Dim k As Long
                For k = LBound(mtch, 1) To UBound(mtch, 1)
                    'If eqaul set value in output and exit the inner loop
                    If mtch(k, 1) = rng(i, j) Then
                        outpt(i, 1) = "True"
                        Exit For
                    End If
                Next k
                'If filled true then exit this for
                If outpt(i, 1) = "True" Then Exit For
            Next j
        Next i

        'Assign the values to the cells.
        .Cells(2, 112).Resize(UBound(outpt, 1), 1).Value = outpt
    End With

 End Sub

【讨论】:

  • 由于某种原因,我得到一个运行时错误 '13': Type mismatch on lastrow = .Cells 在第 8 行。我尝试将它应用到 ThisWorkbook、Sheet1 和 Module 1 中项目窗格,但不断收到相同的错误。我应该尝试从其他地方运行此代码吗?另外,我非常感谢到目前为止的帮助。我已经尝试自学这些材料以防万一还不是很清楚。
  • 这应该在一个模块中@RayJ
  • 第 32 行返回类型不匹配错误 (13)。当我将鼠标悬停在 rng(I, j) 上时,它显示“rng(i, j) = Error 2023”,谷歌称这是一个十六进制格式错误。不确定类型不匹配来自何处,因为我看到两个变量都被声明为变体。逐步运行时也不会发生此错误,直到通过循环进行多次迭代。明天我会继续,看看我是否能找到解决方案并报告。
  • 那么你的数据有错误。要么修复数据,以免出现错误,这是首选方法。或者添加一个检查以在遇到错误时跳过数组中的该项目。 @RayJ 修复底层数据总是比稍后使用创可贴修复更好。
  • 我无法确定输入数据的具体错误是什么,但是在第 30 行添加错误处理程序作为创可贴后,我可以确认此方法确实在输入错误时成功执行了所需的操作没有阻碍它。
猜你喜欢
  • 2015-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多