【发布时间】:2019-09-08 23:13:35
【问题描述】:
[这更像是一个优化问题,而不是代码问题;有更好的地方发这个吗?]
我试图(用最简单的术语)使用 3 列中的宏来索引一个值,索引引用另一个工作表(同一个工作簿)中的表。如果找到值,则输出结果;如果不是,则输出“NOT FOUND”。
我的问题是,在大约 1000 行代码中,它已经需要大约 7 秒才能运行。我之前将代码放在每列的 3 个单独循环中,但将其缩减为一个循环以帮助加快速度,但它仍然很慢。作为参考,我必须在 200K 到 900K 的任何地方运行此代码,具体取决于月份。
我在更繁重的代码中使用了数组,而且这些代码几乎不需要几秒钟,所以我觉得这是我想念/忘记的简单事情;我还听说 VBA 中的工作表函数未优化,可能是这样(以前从未在 VBA 中使用过索引),但这可能是错误信息。
注意: 我尽可能地缩短了代码,以便更容易找到核心问题;代码本身 100% 正确运行,只是速度很慢。我已将声明的变量及其类型放入 cmets 中,并且仅显示了 1 列的查找过程(其他两列的查找基本相同)。
Sub RefreshData()
Call TurnEverythingOff 'Turns off screenupdating, calculations, events, etc.
On Error GoTo Skip
'Variables that are declared (Dim'd) [Put into comments to save space]
'SR_Data is the start row of data [Long]
'ER_Data is the end row of data [Long]
'SC_Data is the start col of data [String]
'EC_Data is the end col of data [String]
'Range/Array_Data are the respective range/array of the above 4 values [Set Range/Variant]
'*****_Col is the numerical value representing the columns for lookup etc. [Long]
'*****_Table is the range that the INDEX/Lookup will view (but in another sheet) [Range]
'Array****Value is to hold the cell string [String]
'Section_DNE is for when values aren't found in INDEX/Lookup [String]
'[MAPPING] Actually performs the lookup/logic
With Data 'Made the sheet codename this in VBA editor
.Activate
ER_Data = .Cells(.Rows.Count, 1).End(xlUp).Row
Set Range_Data = Range(SC_Data & SR_Data & ":" & EC_Data & ER_Data)
Array_Data = Range_Data.Value
'Looking for assistance in speeding **THIS** section up.
For Each DataCell In Range_Data.Columns(1).Cells
'Debug.Print (DataCell.Address)
With Application.WorksheetFunction
'Defines the value in the cell that will need to be looked for
ArrayDisciplineValue = Array_Data(DataCell.Row - SR_Data + 1, Discipline_Col)
ArrayFundNameValue = Array_Data(DataCell.Row - SR_Data + 1, FundName_Col)
Mapping.Activate 'Sheet Codename, sheet contains tables for lookup
'For Discipline Lookup
On Error GoTo ErrorHandle1
ArrayDisciplineValue = _
.Index(Discipline_Table, _
.Match(ArrayFundNameValue, Discipline_Table.Columns(1), 0), _
2)
Data.Activate 'Sheet Codename
'For Discipline Mapping
Array_Data(DataCell.Row - SR_Data + 1, Discipline_Col) = ArrayDisciplineValue
End With
Next DataCell
End With
Range_Data.Value = Array_Data
ErrorHandle1:
'For when the INDEX LOOKUP fails to find the value...
ArrayDisciplineValue = Section_DNE
Resume Next
Skip:
Call TurnEverythingOn
End Sub
预期结果:1000 行需要大约 1 秒(因为它在数组中,它应该更快,不是吗?)
实际结果:1000 行大约需要 7 秒
将其扩展到 200,000 行。
【问题讨论】:
-
注释掉
Mapping.Activate和Data.Activate注意索引/匹配的工作速度要快得多当数据在工作表上时 - 在这种情况下性能会更差 对数组执行查找。当您对工作表进行大量读取/写入时,使用数组是答案,因为它允许您批量处理这些操作:它不会加速所有操作。更多信息请看这里:stackoverflow.com/questions/7031416/… -
那么理想的情况是我将映射表移动到与数据相同的工作表(如果我想保持我的代码相同)吗?有什么方法可以让我的代码保持快速并将映射表放在不同的工作表上;从您提供的链接中, application.match/index 方法不起作用,因为它要慢得多,对吗?即,没有办法有效地跨工作表进行索引/匹配,应该改用 Do While 吗?
-
无需移动映射表 - 您可以毫无问题地跨工作表执行查找。由于您不提供 SC_Data/EC_Data 的值,因此很难准确判断代码中发生了什么
-
嗨蒂姆,我注释掉了 Mapping.Activate 和 Data.Activate;我以前在没有这些的情况下尝试过它,并且由于某种原因它一直在引用活动工作表上的范围,所以我之前一定有不同的东西导致了这种情况。如果有帮助,我可以发布 SC_Data/EC_Data 等值,但仅删除 .activate 部分就已经大大加快了速度!谢谢:)
标签: vba optimization