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 工作表拆分和保存以逗号分隔的许多空白列结束

奇怪的 excel-vba 运行时错误,不会删除现有工作表

索引的访问-SQL Server

通过从 sql server 加入表来更新访问表

MS Access JOIN 访问表与 SQL Server 表

SQL Server 2016 使用 sql 用户通过 azure blob 存储上的 polybase 访问外部表 - 访问被拒绝,因为没有登录映射