【问题标题】:excel vba: recordset joining and performanceexcel vba:记录集加入和性能
【发布时间】:2015-07-04 03:30:00
【问题描述】:

背景

我在 excel VBA 中有一个应用程序,用于对远程数据库进行只读查询。

查询是从 UDF 执行的。我的应用程序将一组数据从记录集对象传递给函数,然后调用 Excel 将数组写入单元格区域的快速过程。

挑战

应用必须能够选择性地返回数据集顶部的字段名称。这对我来说是一个巨大的性能挑战。我知道在 VBA 中附加或附加到二维数组的唯一方法是循环遍历整个数组。通常,通过将recordset.getRows() 对象直接传递给我的UDF,我可以避免这样的循环。但是,当将字段列表和查询结果与循环方法(我知道的唯一方法)相结合时,对于大型查询,我的计算时间会增加一倍或三倍。

我对此进行了基准测试:对于 2k 行和 5 个字段的查询,不包含字段名称的平均计算时间为 4.3 秒,而包含字段名称的平均计算时间为 9.8 秒

我的第一次尝试是在我的选择语句中使用UNION 子句将服务器上的字段名称和记录集组合在一起(我的服务器是 MySQL)。但是,这不起作用,因为 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

【问题讨论】:

  • 在您的“加入”代码中,您看起来像是从二维数组到一维数组(数组数组)。这是故意的吗?
  • 字段名称的目的是为了在Excel工作表上有限数据集的顶部重现它们吗?如果是这样,也许只需使用第二个数组来保存它们。例如:V = Range(row_of_field_names) 将产生一个大小为 V(1 to 1, 1 to num_of_field_names) 的数组。这应该比遍历整个数组更快。
  • @RonRosenfeld - 这是我的第一个想法,但 OP 使用 UDF 将结果传递回工作表,因此只能返回一个数组

标签: mysql arrays excel vba ado


【解决方案1】:

使用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

【讨论】:

  • 谢谢!我对循环成本与application.index() 有一些直觉,这非常不准确。这种方法将额外的开销减少到十分之一秒。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多