VBA:用Excel查询访问。 为什么这么慢?

我发现这个代码在线查询Access并将数据input到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语句和不join的简单select查询。 即使是“select * from [test]”查询所花费的时间也比它应该长得多。

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

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

 Set RST = Con.Execute(SQLQuery) 

一世

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

我不知道是否或为什么可以帮助,但也许会有所帮助? 🙂

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

有关示例代码,请参见http://www.erlandsendata.no/english/index.php?d=envbadacexportdao

请注意,您不应该使用“新build”关键字,因为这会导致意外的结果。

我build议你显式创buildRecordset而不是隐式地使用Execute方法。 在显式创build时,可以设置影响性能的CursorType和LockType属性。

从我看到的,你正在Excel中加载数据,然后closureslogging集。 你不需要更新,计数logging等…所以我的build议是创build一个CursorType = adOpenForwardOnly & LockType = adLockReadOnlyRecordset

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

Recordset Object (ADO)

我用你的代码,在不到7秒钟的时间里,把38列和63780行的表格 – 关于我所期望的 – 和几乎瞬间完成的小logging集合。

这是你正在经历的那种表演吗? 如果是这样,这与我期望的从Excel到ADB后端的ADO连接是一致的。

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

许多公式可能引用查询。 尝试临时打开macros中的手动计算,并在所有查询完成更新时将其closures。

这应该加快一点,但仍然不能解决根本问题。

如果您检索了很多logging,这将解释为什么Range(CellPaste)需要这么长时间。 (如果您在Access中执行查询,则不会检索所有logging,但是如果您执行CopyFromRecordset,则需要所有logging。)

CopyFromRecordset有一个MaxRows参数:

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

尝试,如果设置为一个较低的值(如10左右)改变了性能。

接下来的转机或改进如何?

  1. 打开后,将logging集保存为xml文件(rst.saveToFile xxx),然后让Excel重新打开它。
  2. 一旦打开,将logging集数据放在一个数组(rst.getRows xxx)中,并将该数组复制到活动工作表上
  3. 而且,在任何时候,尽量减less所有的内存/访问需求:打开logging集只读,只转发,closures连接,一旦数据在你身边,等等

我不认为你在比较喜欢。

在Access中,查看查询的数据视图时会发生什么情况:

  • 使用现有的开放连接(并保持打开状态);
  • 一个logging集只部分填满了前几行(并保持打开状态)。
  • 部分结果集显示在一个专用于该任务的网格中,并针对本地数据访问方法Access进行了优化(可能直接使用Access数据库引擎DLL)。

在你的VBA代码中:

  • 一个新的连接打开(然后closures并释放);
  • logging集完全填充所有行(然后closures并释放);
  • 使用非本地数据访问组件将整个结果集读入Excel的通用UI。

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

其次,最重要的是将所读取的行(假设一个完整的结果集)读入UI元素所需的时间,而事实上Excel没有针对该作业进行优化。

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

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

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

这是快速检索logging(<5秒),但突然之间非常缓慢(15秒检索一个logging)。 这是什么引导我到你的post。

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

一旦我把它关了,所有的事情都再次减轻。

问题的10倍是使用您正在使用的光标types/位置。

即使查询执行得非常快,通过networking连接使用dynamic游标也会减慢数据的检索速度。

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

但是,如果您只是读取数据,那么您将保存ADO返回到每个logging的数据库以检查更改。

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