You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何缩短VBA在筛选工作表中跨工作簿范围搜索的运行时间

批量匹配数据性能优化问题

需要遍历工作簿A的1000-3000行,在工作簿B中查找匹配的唯一行(匹配条件为国家+SKU),若找到则将B中对应信息写入A,但当前代码运行耗时数小时。工作簿B原含8-10万行,已提前筛选至800-3000行,尝试过复制筛选数据到新工作簿、取消xlCellTypeVisible、将循环对象从subrng.areas改为rng,但耗时问题仍未解决。

原始VBA代码如下:

Sub Wb_to_APT()

    Dim openedWb As Workbook, APTex As Workbook
    Dim MainView As Worksheet, dis As Worksheet
    Dim disFilter As Range, filterow As Range, rng As Range, subrng As Range
    Dim countryCol1, countryCol2, SKUcol1, SKUcol2, fCol, disFCol, r As Long
    Dim i As Integer


' Must use the APT MainView export to run the macro
    Set MainView = ActiveWorkbook.ActiveSheet


' Tells the user to open the dis file they want to copy from
    Set openedWb = openDataFile
    Set dis = openedWb.Worksheets("DIS")

' Find the last row of the APT export and dis, and fix dynamic column indices
    With dis
        countryCol1 = Application.Match("Territory", MainView.Rows(1), 0)
        countryCol2 = Application.Match("TERRITORY", .Rows(1), 0) + 1
        SKUcol1 = Application.Match("StyleColor", MainView.Rows(1), 0)
        SKUcol2 = Application.Match("PROD_CD", .Rows(1), 0)
        fCol = Application.Match("UFlow1", MainView.Rows(1), 0)
        disFCol = Application.Match("UF1", .Rows(1), 0)
        r = MainView.Cells(Rows.Count, SKUcol1).End(xlUp).Row
        'r_end = .Cells(Rows.Count, SKUcol2).End(xlUp).Row
        Set rng = .Range(.Cells(2, SKUcol2), .Cells(.Cells(Rows.Count, SKUcol2).End(xlUp).Row, SKUcol2))
        Set subrng = rng.SpecialCells(xlCellTypeVisible)
    End With
    
' Iterate through Main View export to find same country-SKU in dis
    With dis
        For i = 2 To r
        ' only check filtered rows in dis
            For Each disFilter In subrng.areas
        ' match countries and SKUs
                If .Cells(disFilter.Row, countryCol2).Value2 = MainView.Cells(i, countryCol1).Value2 And _
                .Cells(disFilter.Row, SKUcol2).Value2 = MainView.Cells(i, SKUcol1).Value2 Then
                    MainView.Cells(i, fCol) = .Cells(disFilter.Row, disFCol).Value2
                    MainView.Cells(i, fCol + 1) = .Cells(disFilter.Row, disFCol + 1).Value2
                    MainView.Cells(i, fCol + 2) = .Cells(disFilter.Row, disFCol + 2).Value2
                    Exit For
                Else
                    MainView.Cells(i, fCol) = "NOT FOUND OR FILTERED OUT"
                End If
            Next disFilter
        Next
    End With

End Sub

优化思路

核心是消除嵌套循环遍历单元格,改用字典实现O(1)时间复杂度的快速匹配,同时关闭Excel的后台操作减少资源消耗:

  • 关闭屏幕刷新、事件触发和自动计算,避免运行中不必要的资源占用
  • 将工作簿B的筛选后数据批量加载到字典,用国家+SKU拼接成唯一键,对应值存储需要写入的3列数据数组
  • 遍历工作簿A时直接通过字典键查找匹配项,一次完成数据写入,彻底解决嵌套循环的性能瓶颈

优化后代码

Sub Wb_to_APT_Optimized()
    Dim openedWb As Workbook, MainView As Worksheet, dis As Worksheet
    Dim countryCol1, countryCol2, SKUcol1, SKUcol2, fCol, disFCol, r As Long
    Dim i As Long, lastRowDis As Long
    Dim matchDict As Object
    Dim keyStr As String
    Dim visibleRows As Range, cell As Range
    
    ' 关闭Excel后台操作,提升运行速度
    Application.ScreenUpdating = False
    Application.EnableEvents = False
    Application.Calculation = xlCalculationManual
    
    Set MainView = ActiveWorkbook.ActiveSheet
    Set openedWb = openDataFile
    Set dis = openedWb.Worksheets("DIS")
    Set matchDict = CreateObject("Scripting.Dictionary")
    
    ' 获取列索引
    With dis
        countryCol1 = Application.Match("Territory", MainView.Rows(1), 0)
        countryCol2 = Application.Match("TERRITORY", .Rows(1), 0) + 1
        SKUcol1 = Application.Match("StyleColor", MainView.Rows(1), 0)
        SKUcol2 = Application.Match("PROD_CD", .Rows(1), 0)
        fCol = Application.Match("UFlow1", MainView.Rows(1), 0)
        disFCol = Application.Match("UF1", .Rows(1), 0)
        r = MainView.Cells(Rows.Count, SKUcol1).End(xlUp).Row
        lastRowDis = .Cells(Rows.Count, SKUcol2).End(xlUp).Row
    End With
    
    ' 将工作簿B的筛选后数据加载到字典
    On Error Resume Next ' 忽略隐藏行的错误
    Set visibleRows = dis.Range(dis.Cells(2, SKUcol2), dis.Cells(lastRowDis, SKUcol2)).SpecialCells(xlCellTypeVisible)
    On Error GoTo 0
    
    If Not visibleRows Is Nothing Then
        For Each cell In visibleRows
            keyStr = dis.Cells(cell.Row, countryCol2).Value2 & "|" & cell.Value2 ' 拼接唯一键
            ' 存储需要写入的3列数据
            matchDict(keyStr) = Array(dis.Cells(cell.Row, disFCol).Value2, _
                                     dis.Cells(cell.Row, disFCol + 1).Value2, _
                                     dis.Cells(cell.Row, disFCol + 2).Value2)
        Next cell
    End If
    
    ' 遍历工作簿A,匹配并写入数据
    With MainView
        For i = 2 To r
            keyStr = .Cells(i, countryCol1).Value2 & "|" & .Cells(i, SKUcol1).Value2
            If matchDict.Exists(keyStr) Then
                ' 批量写入3列数据
                .Cells(i, fCol).Resize(1, 3).Value = matchDict(keyStr)
            Else
                .Cells(i, fCol).Value = "NOT FOUND OR FILTERED OUT"
                ' 清空后续两列(如果需要)
                .Cells(i, fCol + 1).Resize(1, 2).ClearContents
            End If
        Next i
    End With
    
    ' 恢复Excel后台设置
    Application.ScreenUpdating = True
    Application.EnableEvents = True
    Application.Calculation = xlCalculationAutomatic
    
    Set matchDict = Nothing
    MsgBox "数据匹配完成!", vbInformation
End Sub

内容的提问来源于stack exchange,提问作者user75667

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 19:07:46