我正在使用 Excel VBA 清理大型 csv 文件。为此,我将 csv 文件加载到 Access 数据库中,然后使用 SQL 查询执行所有数据转换活动。所以抽象的过程是这样的
打开Excel --> 在开始时单击创建一个access数据库 --> 将csv文件加载到不同的表中 --> 使用adoddb连接在数据库上执行不同的DDl和DML语句 --> 输出最终数据。
我在这里面临的问题是内存使用量总是随着excel的增加而增加。看来access db处理也被添加到excel本身了。所以最终我得到了错误
"System Resource Exceeded"
。
每次执行查询时。内存使用率会上升并且永远不会下降。查询针对 3-4 个表中的大约 10k 到 100k 条记录。
为什么内存使用率永远不会下降?
每次执行 ddl/dml 查询时,我都会打开 adodb 连接并关闭它。我在使用后关闭所有记录集并设置为空。但内存使用量仍然没有下降。
看到不同的相关文章。但大多数人都在讨论同一个 Excel 文件中的数据。就我而言,内存或 Excel 文件中没有保存任何数据。
我在这里看到了微软的一篇文章,其中也谈到了Excel本身的数据。 https://support.microsoft.com/en-us/kb/319998
有人知道这个问题的解决方法吗?
例如:要将数据从 csv 文件加载到表中,我使用以下代码
StrSql = "SELECT * into " & TableName & " FROM [Text;FMT=Delimited;HDR=YES;DATABASE=" & DSPath & "].[" & DSName & "]"
ExecuteSQL StrSql
Private Function ExecuteSQL(Sql As String) As Long
Dim Con As ADODB.Connection
Dim I As Long
Connect Con
Con.Execute Sql, I
ExecuteSQL = I
CloseCon Con
End Function
Public Sub CloseCon(ByRef Con As ADODB.Connection)
If Not Con Is Nothing Then
If Con.State = adStateOpen Then
Con.Close
Set Con = Nothing
End If
End If
End Sub
Public Sub Connect(ByRef Con As ADODB.Connection)
Dim ConStr As String
If Not Con Is Nothing Then
If Con.State = adStateOpen Then
Exit Sub
End If
End If
On Error GoTo err
CloseCon Con
Set Con = New ADODB.Connection
ConStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & DBFile & ";Persist Security Info=False"
Con.Open ConStr, , , -1
Exit Sub
err:
End Sub
这有点帮助。
我尝试使用一个公共连接对象,而不是每次打开和关闭时使用单独的连接对象,该对象从一开始就打开,仅在进程完成时才关闭。这样内存消耗减少了,进程运行的时间也更长了
您的代码看起来不错。该问题是微软在您的参考资料中确认的:“ADO查询使用的内存无法通过关闭和释放ADO对象来回收。释放内存的唯一方法是退出Excel。
所以我们必须时不时退出Excel以回收资源。
“退出 Excel”意味着必须关闭您正在使用的当前工作簿,或者
“退出 Excel”意味着退出 Excel 的所有实例,以便有效地将 Excel 从内存中删除。
广告。 1:在这种情况下,您可以创建一个“父工作簿”来启动另一个包含 ADODB 处理部分的工作簿。它在部分处理后退出,您的父母开始一个新的、其他的工作簿来继续处理,等等。使用一些智能剪切和粘贴来调整退出每个工作簿的时间。
广告 2:在这种情况下,您可以使用例如Word 启动一个新的 Excel.Application 实例,并以与 1 相同的方式进行。只是希望 MS-Office 集成度不要太高,以至于 ADO DLL 在任何 Office 程序运行时都不会退出...
当然,向您的 IT 部门投诉 Microsoft 已确认的错误以安装 Access UI 可能会更好。
我建议使用
With
块来控制 VBA 中所有对象的范围,而不是手动尝试使用辅助函数优雅地管理对象。
这是使用您的代码的示例:
Private Function ExecuteSQL(DBFile As String, Sql As String) As Long
Dim I As Long
With Connect(DBFile)
.Execute Sql, I
.Close
End With
ExecuteSQL = I
End Function
Public Function Connect(ByVal DBFile As String) As ADODB.Connection
On Error GoTo err
Set Connect = New ADODB.Connection
Dim ConStr As String
ConStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & DBFile & ";Persist Security Info=False"
Connect.Open ConStr, , , -1
Return
err:
End Function
用这个
strSystemIDT = Trim(DirPath.Path) + "\IDT.accde" 'mde" 使用 IDTdbCnnctn .连接超时= 30 .Open "Provider=Microsoft.ACE.OLEDB.12.0 ;数据源=" & Trim(strSystemIDT) & ";Jet OLEDB:数据库密码=" & Trim(strPblcPswrdIs) & "" .Properties("Jet OLEDB:每个文件的最大锁定数") = 50000 '9500 .Properties("Jet OLEDB:独占异步延迟") = 0 .Properties("Jet OLEDB:刷新事务超时") = 25000 .Properties("Jet OLEDB:锁定延迟") = 10 '0 '00 .Properties("Jet OLEDB:锁定重试") = 20 .Properties("Jet OLEDB:最大缓冲区大小") = 100000 .Properties("Jet OLEDB:页面超时") = 25000 .Properties("Jet OLEDB:共享异步延迟") = 0 .Properties("Jet OLEDB:回收长值页面") = 0 ' .Properties("Jet OLEDB:事务提交模式") = 1 ' .Properties("Jet OLEDB:用户提交同步") = 1 结束于