Excel-VBA 访问 sql server 表进行选择和插入太慢
Posted
技术标签:
【中文标题】Excel-VBA 访问 sql server 表进行选择和插入太慢【英文标题】:Excel-VBA to access sql server tables for selecting and inserting is too slow 【发布时间】:2016-08-24 15:49:04 【问题描述】:我编写了一个 Excel-VBA 代码来访问一个 SQL Server 数据库(它在网络中,而不是我的计算机中),它有一个包含 10 列和大约 3000 条记录(基本上是抵押贷款)的表。
代码循环遍历这些记录,并且对于每一个记录:进行一些基本计算以生成大约 180 条记录(每个抵押的摊销表),然后将它们插入到新表中(总共大约 540000 条记录)。
它是这样的(我使用 cmets 来提高可读性并避免在这里编写大代码):
Sub amortizationScheduleToSQLServer()
'Some calculation variables go here
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim rs2 As ADODB.Recordset
Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset
Set rs2 = New ADODB.Recordset
Server_Name = "..."
Database_Name = "..."
cn.Open "PROVIDER=SQLOLEDB;DATA SOURCE=" & Server_Name & ";INITIAL CATALOG=" & Database_Name & ";Integrated Security=SSPI;"
SQLStr = "SELECT * FROM TABLE_PRETS"
Set rs = cn.Execute(SQLStr)
If Not (rs.EOF And rs.BOF) Then
rs.MoveFirst
Do Until rs.EOF = True
'Assigning data from table to variables here
'Basic multiplications here, nothing heavy
For i = 1 To paymentsNumber
'More basic calculations and assigning here
SQLStr = "INSERT INTO TABLE_AMORTISSEMENT (N_CONTRAT,MOIS,DATE_ECHEANCE,MENSUALITE,SOLDE_DEPART,CAPITAL_AMORTI," _
& "INTERET_HT,TVA,ASSURANCE,CAPITAL_RESTANT)" _
& "VALUES (" & loanID & ", " & i & ", '" & DateAdd("m", i, startDate) & "', " & Replace(monthlyPayment, ",", ".") & ", " _
& Replace(startingBalance, ",", ".") & ", " & Replace(principal, ",", ".") & ", " & Replace(interestPaymentBT, ",", ".") _
& ", " & Replace(taxOnInterest, ",", ".") & ", " & Replace(insurancePayment, ",", ".") & ", " _
& Replace(remainingBalance, ",", ".") & ");"
Set rs2 = cn.Execute(SQLStr)
Next i
rs.MoveNext
Loop
Else
MsgBox "There are no records in the recordset."
End If
MsgBox "Finished looping through records. "
If rs.State = 1 Then
rs.Close
Set rs = Nothing
End If
If rs2.State = 1 Then
rs2.Close
Set rs2 = Nothing
End If
If cn.State = 1 Then
cn.Close
Set cn = Nothing
End If
End Sub
我通过删除这一行省略了 INSERT 后对这段代码进行了计时:
设置 rs2 = cn.Execute(SQLStr)
代码基本上循环了 3000 条记录并生成了未使用的字符串,它运行了大约 9 秒。 (我不知道这对于 Excel-VBA/SQL Server 是否可以接受)。
但是放回 INSERT 执行行会使代码运行 +1 小时以生成 540000 条记录表。这是正常的吗?如何优化这段代码?
【问题讨论】:
如果程序运行需要 1 小时,这意味着它每秒产生 150 条新记录。考虑到这些都是昂贵的操作,程序需要很长时间才能完成也就不足为奇了。我怀疑您可以做很多事情,除了在第一个SQLStr
语句中可能只查询较少的记录,而不是所有记录。也就是说,如果需要的话。
感谢您的回答。实际上,我稍后会将此代码移至 VB.NET,我想知道它是否会运行得更快。
您可以尝试在一个巨大的语句中添加记录,但不确定它是否会更快。即:INSERT INTO MyTable (Name, ID) VALUES ('First',1), ('Second',2), ('Third',3), ('Fourth',4)
如果我发现我的抵押贷款提供商不是using parameterized queries,我会向其他供应商再融资。
我已经通过连接for循环字符串(每个for循环一个INSERT)将540k INSERT替换为仅3k INSERT,并且它已经运行得更快(13分钟),我想知道我是否可以去进一步。
【参考方案1】:
我在这里说的有点超出了我的舒适范围,但我看到的是 cn.execute 语句创建了一个您从未实际使用过的记录集 (rs2)。根据 ADO 执行方法上的 MSDN 参考,您可以使用选项 (adExecuteNoRecords) 在执行插入时停止创建记录集。也许这样会加快一点?
【讨论】:
执行此操作后代码运行速度提高了 30%。谢谢你的回答。以上是关于Excel-VBA 访问 sql server 表进行选择和插入太慢的主要内容,如果未能解决你的问题,请参考以下文章
Excel-VBA 工作表拆分和保存以逗号分隔的许多空白列结束
MS Access JOIN 访问表与 SQL Server 表
SQL Server 2016 使用 sql 用户通过 azure blob 存储上的 polybase 访问外部表 - 访问被拒绝,因为没有登录映射