VBA:使用Excel查询访问权限。为何这么慢?

时间:2009-10-15 18:30:05

标签: excel vba excel-vba ado jet

我在网上找到这个代码来查询Access并将数据输入到excel(2003)中,但它比它应该慢得多:

Sub DataPull(SQLQuery, CellPaste)
Dim Con As New ADODB.Connection
Dim RST As New ADODB.Recordset
Dim DBlocation As String, DBName As String
Dim ContractingQuery As String

If SQLQuery = "" Then

Else
    DBName = Range("DBName")
    If Right(DBName, 4) <> ".mdb" Then DBName = DBName + ".mdb"

    DBlocation = ActiveWorkbook.Path
    If Right(DBlocation, 1) <> "\" Then DBlocation = DBlocation + "\"

    Con.ConnectionString = DBlocation + DBName
    Con.Provider = "Microsoft.Jet.OLEDB.4.0"
    Con.Open

    Set RST = Con.Execute(SQLQuery)
    Range(CellPaste).CopyFromRecordset RST

    Con.Close
End If

End Sub

问题是此代码需要很长时间。如果我打开Access并在那里运行查询大约需要十分之一的时间。反正有加速吗?或者这可能需要这么长时间?我的所有查询都是简单的选择查询,只有简单的where语句和没有连接。即使是“select * from [test]”查询也需要更长的时间。

编辑:我应该指定“Range(CellPaste).CopyFromRecordset RST”这一行需要很长时间。

10 个答案:

答案 0 :(得分:3)

我不是专家,但我运行几乎完全相同的代码并取得了良好的效果。一个区别是我使用Command对象以及Connection对象。你在哪里

Set RST = Con.Execute(SQLQuery)

Dim cmd As ADODB.Command
Set cmd.ActiveConnection = con
cmd.CommandText = SQLQuery
Set RST = cmd.Execute

我不知道是否或为什么会有所帮助,但也许会有所帮助? : - )

答案 1 :(得分:2)

我认为你没有比较喜欢。

在Access中,当您查看Query的数据视图时会发生什么:

  • 使用现有的开放连接 (并保持开放);
  • 记录集已部分填充 只有前几行(和 保持开放);
  • 部分结果集显示在a中 网格致力于任务和 针对本机数据访问进行了优化 方法访问使用(直接使用 Access数据库引擎DLL, 可能)。

在您的VBA代码中:

  • 打开一个新连接(然后 后来关闭并发布了);
  • 记录集已完全填充 使用所有行(然后关闭和 释放);
  • 将整个结果集读入a Excel的通用UI使用非本机 数据访问组件。

我认为最重要的一点是Access中的数据视图在您要求之前不会获取整个结果集,通常是导航到结果集中的最后一行。 ADO将始终获取结果集中的所有行。

第二个最重要的是将读取的行(假设完整的结果集)读入UI元素所花费的时间,并且事实上Excel没有针对作业进行优化。

打开,关闭和释放连接和记录集应该是微不足道的,但仍然是一个因素。

我认为你需要在流程的每个步骤上做一些时间来找到瓶颈。与Access比较时,请确保获得完整的结果集,例如检查返回的行数。

答案 2 :(得分:1)

我建议您明确地创建Recordset而不是隐式使用。{1}} Execute方法。 显式创建时,您可以设置对性能有影响的CursorType和LockType属性。

从我看到的,你在Excel中加载数据,然后关闭记录集。您不需要更新,统计记录等......所以我的建议是用Recordset创建CursorType = adOpenForwardOnly & LockType = adLockReadOnly

...
RST.Open SQLQuery, Con, adOpenForwardOnly, adLockReadOnly
Range(CellPaste).CopyFromRecordset RST
...

Recordset Object (ADO)

答案 3 :(得分:1)

由于您使用的是Access 2003,因此使用DAO,使用Jet引擎会更快。

请参阅http://www.erlandsendata.no/english/index.php?d=envbadacexportdao了解示例代码。

请注意,您绝不应使用“As New”关键字,因为这会导致意外结果。

答案 4 :(得分:1)

我使用了你的代码并在不到7秒的时间内完成了38列和63780行的表格 - 大概是我所期望的 - 并且几乎瞬间完成了较小的记录集。

这是您遇到的那种表现吗?如果是这样,它与我从Excel到MDB后端的ADO连接所期望的一致。

如果你看到的性能比这要低得多,那么必然会有一些影响事物的局部环境条件。

答案 5 :(得分:1)

很多公式可能会引用查询。尝试暂时打开宏中的手动计算,并在所有查询完成更新后将其关闭。

这应该加快一点,但仍然无法解决潜在的问题。

答案 6 :(得分:0)

如果您检索了大量记录,则可以解释为什么Range(CellPaste)需要这么长时间。 (如果在Access中执行查询,则不会检索所有记录,但如果执行CopyFromRecordset,则需要所有记录。)

CopyFromRecordset有一个MaxRows参数:

Public Function CopyFromRecordset ( _
    Data As Object, _
    <OptionalAttribute> MaxRows As Object, _
    <OptionalAttribute> MaxColumns As Object _
) As Integer

尝试将此值设置为较低值(如10左右)会改变性能。

答案 7 :(得分:0)

以下转变或改进如何:

  1. 打开后,将记录集保存为xml文件(rst.saveToFile xxx),然后让Excel重新打开它。
  2. 打开后,将记录集数据放入一个数组(rst.getRows xxx),并将该数组复制到活动工作表上
  3. 并且,在任何时候,最小化所有内存/访问要求:将记录集打开为只读,仅转发,一旦数据在您身边就关闭连接等。

答案 8 :(得分:0)

我不知道它是否有帮助,但我使用VBA和ADO连接到Excel电子表格。

它正在快速检索记录(<5秒),但突然间它非常缓慢(15秒检索一条记录)。这就是引导我发帖的原因。

我意识到我不小心打开了Excel文件(我一直在编辑它)。

一旦我关闭它,所有人都再次快速闪电。

答案 9 :(得分:0)

10次中的9次问题与您正在使用的光标类型/位置有关。

通过网络连接使用动态游标可能会减慢数据检索速度,即使查询执行速度非常快。

如果您想快速获取大量数据,则需要在连接上使用CursorLocation = adUseClient。这意味着你只有一个静态的本地光标,所以你不会从其他用户那里得到实时更新。

但是 - 如果您只是在阅读数据,那么您将保存ADO返回到每个单独记录的数据库以检查更改。

我最近更改了这个,因为我有一个简单的循环,填充列表项,每个循环大约需要0.3秒。不要慢,但即使是30秒的1000条记录!仅更改光标位置可让整个过程在1秒内完成。