Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance Excel VBA-UDF包装VLOOKUP时行为奇怪且性能差_Performance_Vba_Excel - Fatal编程技术网

Performance Excel VBA-UDF包装VLOOKUP时行为奇怪且性能差

Performance Excel VBA-UDF包装VLOOKUP时行为奇怪且性能差,performance,vba,excel,Performance,Vba,Excel,我想写一个用户定义的函数来包装VLOOKUP。它只需要引用应该从中导入数据的列,并且它将执行一个VLOOKUP,假设ID位于列a中,并且要搜索的行少于3000行 Function AutoVlookup( importFrom As Range) As Variant Dim arg1, arg2, arg3, arg4 As Variant Dim arg1Str, arg2Str As String arg1Str = "$A" & Application.

我想写一个用户定义的函数来包装VLOOKUP。它只需要引用应该从中导入数据的列,并且它将执行一个VLOOKUP,假设ID位于列a中,并且要搜索的行少于3000行

Function AutoVlookup( importFrom As Range) As Variant
    Dim arg1, arg2, arg3, arg4 As Variant
    Dim arg1Str, arg2Str As String

    arg1Str = "$A" & Application.Caller.row 'get ID
    arg1 = Application.Caller.Parent.Range(arg1Str)
    arg2Str = "$A$1:$" & Split(cells(1, importFrom.column).Address, "$")(1) & "$3000"
    arg2 = importFrom.Parent.Range(arg2Str) 'get range to search in (in other workbook)
    arg3 = importFrom.column 'get column to return
    arg4 = False 'exact match

    AutoVlookup = Application.WorksheetFunction.VLookup(arg1, arg2, arg3, arg4)   
End Function
我遇到了两个问题

首先,执行时间很糟糕。将这个公式运行1000次需要几分钟,而没有包装在UDF中的同一个VLOOKUP速度非常快

其次,当我第一次用
=AutoVLookup()
填充一列时,每一行都会错误地显示相同的结果,直到有东西触发它们重新计算

我做错了什么


编辑,回答:

下面是我根据Santosh和Charles的建议编写的代码:

Function EasyLookup(importFrom As Range) As Variant
    Application.Volatile False 'does not recalculate whenever cells on sheet change

    Dim Id As String
    Dim match As Integer
    Dim importColumnAddress As String
    Dim initialCalculationSetting As XlCalculation
    Dim initialScreenUpdateMode As Boolean
    Dim initialEnableEventsMode As Boolean

    'saving the settings, to be reverted later
    initialScreenUpdateMode = Application.ScreenUpdating
    initialCalculationSetting = Application.Calculation
    initialEnableEventsMode = Application.EnableEvents
    'changes screen update and calculation settings for performance
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    Application.EnableEvents = False

    'find ID on formula's sheet
    Id = Application.caller.Parent.Cells(Application.caller.row, 1).value
    'find row with ID on column A of data source sheet
    match = Application.WorksheetFunction.match(Id, importFrom.Parent.Range("$A$1:$A$4000"), 0) 'assumes no more than 4000 rows.

    'retrieve value from importFrom's column, on the row where ID was found
    importColumnAddress = Split(Cells(1, importFrom.column).Address, "$")(1)
    importColumnAddress = importColumnAddress & ":" & importColumnAddress
    EasyLookup = Application.WorksheetFunction.Index(importFrom.Parent.Range(importColumnAddress), match)

    'revert performance tweaks
    Application.ScreenUpdating = initialScreenUpdateMode
    Application.Calculation = initialCalculationSetting
    Application.EnableEvents = initialEnableEventsMode
End Function
它的速度要快得多,因为它使用索引/匹配而不是VLOOKUP,所以不会读入那么多数据。它也不会在工作表中的单元格每次更改时重新计算。

请尝试以下代码:

Function AutoVlookup(importFrom As Range) As Variant

    Application.Volatile False
    Application.Calculation = xlCalculationManual
    Application.ScreenUpdating = False
    Application.EnableEvents = False

    Dim arg1, arg2, arg3, arg4 As Variant
    Dim arg1Str, arg2Str As String
    Dim rng As Object

    Set rng = Application.Caller
    arg1Str = "$A" & rng.Row    'get ID
    Set arg1 = Application.Caller.Parent.Range(arg1Str)

    arg2Str = "$A$1:$" & Split(Cells(1, importFrom.Column).Address, "$")(1) & "$3000"
    Set arg2 = importFrom.Parent.Range(arg2Str)    'get range to search in (in other workbook)

    arg3 = importFrom.Column    'get column to return
    arg4 = False    'exact match

    AutoVlookup = Application.VLookup(arg1, arg2, arg3, arg4)

    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic
    Application.EnableEvents = True
End Function
请尝试以下代码:

Function AutoVlookup(importFrom As Range) As Variant

    Application.Volatile False
    Application.Calculation = xlCalculationManual
    Application.ScreenUpdating = False
    Application.EnableEvents = False

    Dim arg1, arg2, arg3, arg4 As Variant
    Dim arg1Str, arg2Str As String
    Dim rng As Object

    Set rng = Application.Caller
    arg1Str = "$A" & rng.Row    'get ID
    Set arg1 = Application.Caller.Parent.Range(arg1Str)

    arg2Str = "$A$1:$" & Split(Cells(1, importFrom.Column).Address, "$")(1) & "$3000"
    Set arg2 = importFrom.Parent.Range(arg2Str)    'get range to search in (in other workbook)

    arg3 = importFrom.Column    'get column to return
    arg4 = False    'exact match

    AutoVlookup = Application.VLookup(arg1, arg2, arg3, arg4)

    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic
    Application.EnableEvents = True
End Function

UDF速度慢的主要原因是:
1)您强制它将3000行数据从Excel导入VBA变量,然后将3000行数据传递回VLOOKUP,而不是仅仅使用范围的引用
2)您没有绕过VBE刷新错误

请参阅关于构建更快查找等的一系列文章在


您的UDF在引用不包含在importfrom范围内的单元格的情况下也无法正常工作。

最后,我不确定我是否理解您试图实现的目标:它会不会更简单(更有效)要使用索引或隐式引用而不是VLOOKUP?

UDF速度慢的主要原因是:
1)您强制它将3000行数据从Excel导入VBA变量,然后将3000行数据传递回VLOOKUP,而不仅仅是使用范围的引用
2)您没有绕过VBE刷新bug

请参见


上关于构建快速查找等的一系列帖子。此外,如果UDF引用的单元格不包含在importfrom范围内,则UDF将无法正常工作。

最后,我不确定我是否理解您试图实现的目标:它是否会更简单(且效率更高)使用索引或隐式引用而不是VLOOKUP?

快速注意:当您执行“Dim arg1Str,arg2Str As String”时,arg1Str被声明为变量,而不是字符串^^^真的吗?因此,变量类型仅适用于列表中的最后一个|它适用于与相邻的任何变量“As”(是的,最后一个)。@Tristan虽然变量被错误地声明为
Dim arg1、arg2、arg3、arg4变量
,而不是
Dim arg1变量、arg2变量、arg3变量、arg4变量
,但幸运的是它们仍然是变量(bcoz未使用特定数据类型声明),这是函数所需的。请查看此链接是的,您需要声明所有内容。在同一行中,唯一可以忽略的是第二个变量及其后的“Dim”。快速注意:当您执行“Dim arg1Str,arg2Str As String”时arg1str被声明为变量,而不是字符串^^真的吗?因此变量类型仅适用于列表中的最后一个变量?:|它适用于与“as”相邻的任何变量(是的,在您的示例中是最后一个)@Tristan虽然变量被错误地声明为变量
Dim arg1、arg2、arg3、arg4,而不是
Dim arg1为变量、arg2为变量、arg3为变量、arg4为变量
,但幸运的是它们仍然是变量(bcoz未使用特定数据类型声明)这正是函数所需要的。查看此链接是的,你需要声明所有内容。在同一行中,唯一可以忽略的是“Dim”对于第二个变量和以后的变量。谢谢!这解决了问题1-Excel不再冻结。但是,我仍然有问题2-当我用这个公式填充1000行列时,它立即计算最后200,然后前800都显示相同的值几分钟。谢谢!这解决了问题1-Excel不再冻结.然而,我仍然有问题2-当我用这个公式填充1000行的列时,它会立即计算最后200行,然后前800行在几分钟内显示相同的值。