excel vba:记录集连接和性能
excel vba: recordset joining and performance
背景
我在 excel VBA 中有一个应用程序,用于对远程数据库进行只读查询。
查询是从 UDF 执行的。我的应用程序将数据数组从记录集对象传递到函数,并调用 Excel 将数组写入单元格区域的快速过程。
挑战
应用程序必须能够选择 return 数据集顶部的字段名称。这对我来说是一个巨大的性能挑战。我知道在 VBA 中附加或前置到二维数组的唯一方法是遍历整个数组。通常,我通过将 recordset.getRows()
对象直接传递到我的 UDF 来避免这样的循环。但是,当将字段列表和查询结果与循环方法(我知道的唯一方法)结合使用时,我将大量查询的计算时间增加了一倍或三倍。
我对此进行了基准测试:对于 2k 行和 5 个字段的查询,不包含字段名称的平均计算时间为 4.3 秒,而 9.8 秒 与字段名称
我的第一个尝试是在我的 select 语句(我的服务器是 MySQL)中使用 UNION
子句组合服务器上的字段名称和记录集。但是,这不起作用,因为 UNION 强制数据类型相等,隐式地将我的数字数据转换为字符串。要将它们转换回来,我必须遍历数组,否定任何获得的效率。
我的问题
是否可以调用记录集对象或 VBA 数组的任何对象方法,以在不遍历整个大数组的情况下将行添加到大数组? 在执行 MySQL 查询之前,字段名称都是已知的。
我加入数组的循环如下。定义一个长度为记录集 + 1 的新数组 arr
,然后遍历它,首先添加字段,然后记录集数组的每一行:
For r = LBound(arr, 1) To UBound(arr, 1)
If r = LBound(arr, 1) Then
arr(r) = fieldArray
Else
arr(r) = Application.Index(rs_array, r - 1, 0)
End If
Next
使用 Application.Index
可能是组合数组的最慢方法:改用常规嵌套循环,您甚至不会注意到任何命中 -
Sub TT()
Dim a(1 To 2000, 1 To 10)
Dim b(1 To 2000, 1 To 10)
Dim cc(1 To 2000)
Dim r, c, t
t = Timer
For r = 1 To 2000
For c = 1 To 10
b(r, c) = a(r, c)
Next c
Next r
Debug.Print "Loop", Timer - t '>> 0.015625 sec
t = Timer
For r = 1 To 2000
cc(r) = Application.Index(a, r, 0)
Next r
Debug.Print "Index", Timer - t '>> 4.195313 sec
End Sub
背景
我在 excel VBA 中有一个应用程序,用于对远程数据库进行只读查询。
查询是从 UDF 执行的。我的应用程序将数据数组从记录集对象传递到函数,并调用 Excel 将数组写入单元格区域的快速过程。
挑战
应用程序必须能够选择 return 数据集顶部的字段名称。这对我来说是一个巨大的性能挑战。我知道在 VBA 中附加或前置到二维数组的唯一方法是遍历整个数组。通常,我通过将 recordset.getRows()
对象直接传递到我的 UDF 来避免这样的循环。但是,当将字段列表和查询结果与循环方法(我知道的唯一方法)结合使用时,我将大量查询的计算时间增加了一倍或三倍。
我对此进行了基准测试:对于 2k 行和 5 个字段的查询,不包含字段名称的平均计算时间为 4.3 秒,而 9.8 秒 与字段名称
我的第一个尝试是在我的 select 语句(我的服务器是 MySQL)中使用 UNION
子句组合服务器上的字段名称和记录集。但是,这不起作用,因为 UNION 强制数据类型相等,隐式地将我的数字数据转换为字符串。要将它们转换回来,我必须遍历数组,否定任何获得的效率。
我的问题
是否可以调用记录集对象或 VBA 数组的任何对象方法,以在不遍历整个大数组的情况下将行添加到大数组? 在执行 MySQL 查询之前,字段名称都是已知的。
我加入数组的循环如下。定义一个长度为记录集 + 1 的新数组 arr
,然后遍历它,首先添加字段,然后记录集数组的每一行:
For r = LBound(arr, 1) To UBound(arr, 1)
If r = LBound(arr, 1) Then
arr(r) = fieldArray
Else
arr(r) = Application.Index(rs_array, r - 1, 0)
End If
Next
使用 Application.Index
可能是组合数组的最慢方法:改用常规嵌套循环,您甚至不会注意到任何命中 -
Sub TT()
Dim a(1 To 2000, 1 To 10)
Dim b(1 To 2000, 1 To 10)
Dim cc(1 To 2000)
Dim r, c, t
t = Timer
For r = 1 To 2000
For c = 1 To 10
b(r, c) = a(r, c)
Next c
Next r
Debug.Print "Loop", Timer - t '>> 0.015625 sec
t = Timer
For r = 1 To 2000
cc(r) = Application.Index(a, r, 0)
Next r
Debug.Print "Index", Timer - t '>> 4.195313 sec
End Sub