缓慢的VBA-SQL(620插入250秒),网络或代码?

时间:2014-03-07 14:02:14

标签: sql performance vba networking firebird

所以我在VBA(Excel)中编写了一个应用程序来与Firebird数据库进行交互。该数据库曾用于本地运行,但已将其移至我通过VPN访问的托管解决方案。 (我家里有25/4 Mb的互联网连接)

现在当它在本地运行时,我的代码很草率,我使用生成的SQL语句,我将变量连接到sqlstring然后执行。即:"插入BLA ..& VALUE1& VALUE2"等

这很好用,但是当移动到托管解决方案时,速度很慢,623次插入需要450秒。

好的,所以我意识到我第一次没做对,所以我把代码重写为paramterized sql查询,代码如下。

Set adoComm = New ADODB.Command
Set adoConn = New ADODB.Connection
Call clientcleancall
mytimer = Timer
Dim sconnect As String

sconnect = "Provider=MSDASQL.1;DSN=SOSARemoteTesting;auto_commit=true"

Dim Conn As New ADODB.Connection

adoConn.Open sconnect
adoComm.ActiveConnection = adoConn
Application.ScreenUpdating = False


adoComm.Parameters.Append adoComm.CreateParameter("p1", adChar, adParamInput, 40)
adoComm.Parameters.Append adoComm.CreateParameter("p2", adChar, adParamInput, 40)
adoComm.Parameters.Append adoComm.CreateParameter("p3", adChar, adParamInput, 35)
adoComm.Parameters.Append adoComm.CreateParameter("p4", adChar, adParamInput, 20)
adoComm.Parameters.Append adoComm.CreateParameter("p5", adChar, adParamInput, 20)
adoComm.Parameters.Append adoComm.CreateParameter("p6", adInteger, adParamInput, 50)
adoComm.Parameters.Append adoComm.CreateParameter("p7", adChar, adParamInput, 60)
adoComm.Parameters.Append adoComm.CreateParameter("p8", adChar, adParamInput, 60)
adoComm.Parameters.Append adoComm.CreateParameter("p9", adChar, adParamInput, 60)
adoComm.Parameters.Append adoComm.CreateParameter("p10", adChar, adParamInput, 60)
adoComm.Parameters.Append adoComm.CreateParameter("p11", adChar, adParamInput, 10)
adoComm.Parameters.Append adoComm.CreateParameter("p12", adChar, adParamInput, 100)

Dim s As String

s = "INSERT INTO HARDWARE_ASSETS (HW_SERIAL, HW_NAME, HW_MACH_ID, HW_CUST, HW_INSTALL," & _
"HW_INSTALL_DATE, HW_LOCATION, HW_STATUS, HW_BILLABLE, HW_OWNER, HW_VIRTUAL, HW_SOURCE) " & _
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"

adoComm.CommandText = s

For lrow = 3 To 624
      'flex1.Row = lRow
      'flex1.Col = 0
        Cells(lrow, 1).Select
        adoComm.Parameters("P1").value = Selection
        adoComm.Parameters("P2").value = Selection.Offset(0, 1).value
        adoComm.Parameters("P3").value = Selection.Offset(0, 2).value
        adoComm.Parameters("P4").value = Selection.Offset(0, 3).value
        'adoComm.Parameters("P5").AppendChunk (Mid(GetString(flex1.Text), 1, 20000))
        adoComm.Parameters("P5").value = Selection.Offset(0, 4).value
        adoComm.Parameters("P6").value = Selection.Offset(0, 5).value
        adoComm.Parameters("P7").value = Selection.Offset(0, 6).value
        adoComm.Parameters("P8").value = Selection.Offset(0, 7).value
        adoComm.Parameters("P9").value = Selection.Offset(0, 8).value
        adoComm.Parameters("P10").value = Selection.Offset(0, 9).value
        adoComm.Parameters("P11").value = Selection.Offset(0, 10).value
        adoComm.Parameters("P12").value = Selection.Offset(0, 11).value
        adoComm.Execute s, , adExecuteNoRecords

Next lrow

    bcommited = True

adoConn.Close
Application.ScreenUpdating = True
MsgBox (Timer - mytimer)

现在我的执行时间有了很大改善,但仍然有621个插入需要250秒。

要访问服务器,我必须通过VPN上的防火墙进行身份验证。我做的一些故障是ping服务器,第一个数据包总是花费大约200毫秒,其余的大约需要100个。平均值通常在150毫秒左右。 firebird数据库被大型组织使用,有些像Terabyte一样大,用于生产,所以我不认为数据库的基于文件的性质是罪魁祸首。

我的具体问题: 1)我的代码需要多长时间才能执行,而当前的代码需要多长时间? 2)我还能做些什么来简化我的代码? 3)如果1& 2不是罪魁祸首我想与我的网络管理员讨论事情,因为认为高ping时间可能会加剧问题?

感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

COM ADO可以非常快。您正在做的就是获得最佳性能:重用相同的Command对象并使用参数提供值。企业数据库中的621个插入,即使有12个参数,也应该采用一秒或几个的顺序。因此,低性能几乎肯定不是由于您的代码。

尝试三件事来追踪瓶颈:

  1. 只评论一行:

    adoComm.Execute s, , adExecuteNoRecords
    

    因此,您只需创建命令及其参数,然后在电子表格中压缩,将值分配给参数。这将告诉您读取和加载本地值需要多长时间。 Excel在枚举自己的原生Range对象时有时可能会非常慢,但我不知道这是否是一个问题,直到你测试它。

  2. 在单独的测试子中,打开与FireBird数据库的连接,创建一个简单的命令,如SELECT 1 FROM rdb$database 1 ,然后执行命令621次。这将告诉您与服务器联系并等待响应所需的时间。

  3. 重复#2,但在查询中添加12个参数。只需在开头设置一次。这将告诉您在线路上传输参数值需要多少额外时间。 SQL类似于 1

    SELECT ? AS P1, ? AS P3, ? AS P3, ? AS P4 .. FROM rdb$database
    
  4. 1 我不熟悉FireBird SQL,但this forum entrythis official FAQ建议FireBird需要'magic'表名rdb$database才能进行单例选择...也许你(OP)已经知道了

答案 1 :(得分:0)

在完成这项工作后,网络是一个促成因素。 ping时间高达200毫秒,即使参数化查询也需要很长时间。

我的解决方案是使用Block insert。

Execute BLOCK as begin
Full insert;
Full insert;
Full insert;
end

621插入的运行时间现在为5秒。更加可管理和现实。唯一的限制是字符限制为~58k。这意味着您必须修改循环,以便每个块只执行100次左右的插入。