能否在Excel VBA中并行执行PostgreS ODBC SQL查询以提升性能?
实现VBA并行执行PostgreSQL SQL查询的几种方案
你说得没错,VBA本身确实没有原生的多线程支持,但咱们有几种实用的办法来绕过这个限制,实现并行执行你的27条SQL查询,充分利用数据库的富余资源,提升整体性能。下面按易用性和稳定性排序,给你详细介绍:
1. 优先推荐:用Power Query(Get & Transform)并行加载
这是最简单且高效的方案,几乎不用写代码,Power Query本身就支持异步并行处理数据请求,完美适配你的场景:
- 操作步骤:
- 打开Excel的「数据」选项卡,点击「获取数据」→「从其他源」→「从ODBC」
- 选择你的PostgreSQL ODBC数据源,输入第一条SQL查询,点击「确定」
- 在Power Query编辑器里确认数据无误后,点击「关闭并上载至」,选择对应的目标工作表,设置加载位置
- 重复上述步骤,为27条SQL分别创建独立的Power Query查询,每个对应不同的工作表
- 需要刷新数据时,直接点击「数据」→「全部刷新」,Power Query会自动并行处理所有查询请求
这种方式的优势在于:无需维护复杂的VBA代码,Power Query会自动处理连接池、并行调度,而且性能表现非常稳定。
2. VBA内用ADO异步查询实现并行
如果必须用VBA来控制流程,可以利用ADO的异步执行特性,在同一个Excel实例里同时发起多个查询请求,不用等待前一个完成再执行下一个:
代码示例(简化版)
首先要确保你的VBA项目引用了「Microsoft ActiveX Data Objects x.x Library」(版本选最新的即可):
' 声明带事件的ADO连接对象,每个查询对应一个连接 Private WithEvents connQuery1 As ADODB.Connection Private WithEvents connQuery2 As ADODB.Connection ' ... 为27个查询声明对应的连接对象(或者用数组来批量管理更高效) Sub StartAsyncQueries() Dim connString As String connString = "你的PostgreSQL ODBC连接字符串" ' 比如:DRIVER={PostgreSQL Unicode};SERVER=xxx;DATABASE=xxx;UID=xxx;PWD=xxx; ' 初始化第一个查询连接并异步执行 Set connQuery1 = New ADODB.Connection connQuery1.Open connString connQuery1.Execute "SELECT * FROM your_table_1", , adAsyncExecute ' 初始化第二个查询连接并异步执行,无需等待第一个完成 Set connQuery2 = New ADODB.Connection connQuery2.Open connString connQuery2.Execute "SELECT * FROM your_table_2", , adAsyncExecute ' ... 依次初始化并执行剩下的25个查询 End Sub ' 第一个查询完成后的回调事件 Private Sub connQuery1_ExecuteComplete(ByVal RecordsAffected As Long, ByVal pError As ADODB.Error, _ adStatus As ADODB.EventStatusEnum, ByVal pCommand As ADODB.Command, _ ByVal pRecordset As ADODB.Recordset, ByVal pConnection As ADODB.Connection) If adStatus = adStatusOK Then ' 将结果集复制到指定工作表的A1单元格开始 ThisWorkbook.Sheets("Sheet1").Range("A1").CopyFromRecordset pRecordset Else ' 处理错误,比如记录日志 MsgBox "查询1执行失败:" & pError.Description End If ' 关闭连接并释放资源 pConnection.Close Set connQuery1 = Nothing End Sub ' 第二个查询完成后的回调事件 Private Sub connQuery2_ExecuteComplete(ByVal RecordsAffected As Long, ByVal pError As ADODB.Error, _ adStatus As ADODB.EventStatusEnum, ByVal pCommand As ADODB.Command, _ ByVal pRecordset As ADODB.Recordset, ByVal pConnection As ADODB.Connection) If adStatus = adStatusOK Then ThisWorkbook.Sheets("Sheet2").Range("A1").CopyFromRecordset pRecordset Else MsgBox "查询2执行失败:" & pError.Description End If pConnection.Close Set connQuery2 = Nothing End Sub ' ... 为剩下的查询编写对应的回调事件
注意事项
- 可以用数组来批量管理
ADODB.Connection对象,避免写27个重复的事件处理函数 - 注意数据库的最大并发连接数限制,不要一次性发起超过数据库允许的连接请求
- 回调事件里要做好错误处理,避免单个查询失败影响整体流程
3. 用WSH启动多Excel实例并行执行
如果上述两种方案都不满足需求,还可以通过Windows Script Host(WSH)启动多个独立的Excel实例,每个实例负责执行一条SQL查询,实现真正的进程级并行:
核心思路
- 把单个查询的逻辑封装成一个独立的宏(比如接收SQL语句和目标工作表名作为参数)
- 主工作簿里用
WScript.Shell启动多个Excel实例,每个实例打开当前工作簿并执行指定的查询宏 - 查询完成后,子实例可以自动关闭,或者把结果写回主工作簿(需要注意跨进程访问的权限问题)
简化代码示例
Sub RunParallelQueries() Dim wsh As Object Dim sqlQueries As Variant Dim sheetNames As Variant Dim i As Integer Set wsh = CreateObject("WScript.Shell") sqlQueries = Array("SELECT * FROM table1", "SELECT * FROM table2", "SELECT * FROM table3") ' 替换成你的27条SQL sheetNames = Array("Sheet1", "Sheet2", "Sheet3") ' 对应目标工作表 ' 循环启动子进程 For i = LBound(sqlQueries) To UBound(sqlQueries) ' 启动新的Excel实例,打开当前工作簿并执行指定宏,传递SQL和工作表名参数 wsh.Run "excel.exe """ & ThisWorkbook.FullName & """ /eRunSingleQuery """ & sqlQueries(i) & """ """ & sheetNames(i) & """", 0, False Next i Set wsh = Nothing End Sub ' 供子实例执行的单个查询宏 Sub RunSingleQuery(sql As String, sheetName As String) Dim conn As ADODB.Connection Dim rs As ADODB.Recordset Dim connString As String connString = "你的ODBC连接字符串" Set conn = New ADODB.Connection conn.Open connString Set rs = conn.Execute(sql) ThisWorkbook.Sheets(sheetName).Range("A1").CopyFromRecordset rs rs.Close conn.Close Set rs = Nothing Set conn = Nothing ' 执行完成后关闭Excel实例(可选) Application.Quit End Sub
注意事项
- 27个Excel实例可能会占用较多系统内存,建议分批并行(比如一次跑5-10个)
- 跨进程访问工作簿时要注意文件锁定问题,最好让子实例直接写入自己负责的工作表,主实例最后统一整理
- 要确保子实例的宏安全设置允许执行宏
内容的提问来源于stack exchange,提问作者Ratilius
相关产品推荐
相关产品推荐

