Sql server 如何使VB.NET代码从SQL Server表中检索单行的速度与VB6一样快

Sql server 如何使VB.NET代码从SQL Server表中检索单行的速度与VB6一样快,sql-server,vb.net,stored-procedures,adodb,recordset,Sql Server,Vb.net,Stored Procedures,Adodb,Recordset,我们的任务是将遗留的VB6应用程序转换为VB.Net 代码转换已经完成了一段时间,我们现在正在测试 测试工具套件的一部分是能够重复运行系统负载测试 我们观察到,使用VB.NET版本运行测试所需的时间明显更长 作为分析的一部分,我们创建了一个测试,该测试只加载使用ADODB访问SQL数据库的应用程序部分 这就是性能问题所在 特别是,在从相对较小的表(例如20列左右)中按键检索单行时,会出现此问题 每个表的行中的每个条目都有一个唯一的int键和一个唯一的varchar键 在这两个版本中,检索都是通过

我们的任务是将遗留的VB6应用程序转换为VB.Net

代码转换已经完成了一段时间,我们现在正在测试

测试工具套件的一部分是能够重复运行系统负载测试

我们观察到,使用VB.NET版本运行测试所需的时间明显更长

作为分析的一部分,我们创建了一个测试,该测试只加载使用ADODB访问SQL数据库的应用程序部分

这就是性能问题所在

特别是,在从相对较小的表(例如20列左右)中按键检索单行时,会出现此问题

每个表的行中的每个条目都有一个唯一的int键和一个唯一的varchar键

在这两个版本中,检索都是通过SQL Server存储过程进行的。键值作为ADODB.Command后面的ADODB.Parameter传递。事实上,两个版本中使用了相同的数据库实例(使用相同的存储过程)。在每次测试之前,我们删除表中所有预先存在的行

两个版本中与数据库的连接字符串为:

驱动程序={SQL Server};服务器=MYCOMPUTER\SQLEXPRESS;数据库=数据库名称

用于检索的存储过程是:

SELECT * From Table1 WHERE TheKey = @pTheKey
其中@pTheKey是ADODB.Parameter的值

为了得到以下结果,我们首先加载每个表,每个表有5000行。插入所用的时间大致相同,不过VB.Net稍快一些

行的加载顺序为5000到1(即向后)

然后,我们运行以下检索测试:

1] 从表1中,按1到5000的顺序检索10000行
2] 从表1中,以随机顺序检索10000行
3] 从表1中,以随机顺序检索(或要求检索)10000个不存在的行

在上面的示例中,前5000次检索使用int键,最后5000次检索使用varchar键

表2重复了该试验

检索每一行后,我们检查数据以确保检索到(或未检索到)正确的行

以下是检索的典型计时结果(所有时间均以毫秒为单位):

VB6表1测试1:3926
VB6表1测试2:2740
VB6表1测试3:4444
VB6表2测试1:3882
VB6表2测试2:2596
VB6表2测试3:4635

.NET表1测试1:241715
.NET表1测试2:212798
.NET表1测试3:238280
.NET表2测试1:122237
.NET表2测试2:75840
.NET表2测试3:244343

NET检索所需的时间大约要长30到75倍。在100毫秒左右的多个测试中,时间完全可重复

以下是执行单行检索的VB6代码(或在测试类型3的情况下失败)

其中SQLADODBCOMAND是ADODB.Command对象,附加的ADODB.Parameter设置为键值

以下是用于执行单行检索的.NET代码(或在测试类型3的情况下失败)

预期问题:

1] 所有与SQL相关的代码都驻留在一个模块中
2] 负载测试期间没有运行其他代码
3] 只有一个数据库连接处于活动状态,即负载测试连接
4] 从返回的记录集中检索记录集值已被剥离,以验证从返回的记录集对象中提取数据不会影响时间
5] VB6对ADO的引用是“MicrosoftActiveX数据对象6.0BackCompat库”
6] NET对ADO的引用是“Microsoft ActiveX数据对象2.8库”

感激地接受任何见解或建议

更新(几天后): 将源代码从ADODB转换为ADO.NET后,插入所用的时间与VB6和ADODB所用的时间大致相同

然而,在检索方面,检索速度是VB6的两倍(至少)和ADODB的一百多倍

(对于作为搜索的一部分阅读本文的任何新手,请查看System.Data.SqlClient中的界面。)


我们将运行更多的测试来比较单记录更新的结果。

嗯,问题是ADO REOCRDSET是不受管理的代码。因此,.net必须在托管代码和非托管代码之间不断地“封送”。这包括将数据类型封送至.net变量类型或从.net变量类型封送至.net变量类型。那要花很多钱

我的意思是,您可以尝试将此代码作为测试:

    Dim t As DateTime
    Debug.Print("start")

    t = Date.Now

    Using con As New SqlConnection(My.Settings.Test3)
        Dim strSQL As String = "SELECT * from tblHotels where ID  = @ID"
        Dim cmdSQL As New SqlCommand(strSQL, con)
        cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = 19
        con.Open()
        Dim rst As New DataTable
        For i = 1 To 10000
            rst.Clear()
            rst.Load(cmdSQL.ExecuteReader)
        Next

    End Using

    Debug.Print("time = " & ((Date.Now.Ticks - t.Ticks) / 10000000).ToString)
现在我在上面运行的是一台dumpser fire笔记本电脑,带有1.7 ghz i3(非常低端)

我得到的时间超过6.6428576秒,当然也就是6642密耳秒

我想,如果硬件更好,上述数字还会下降一半

现在,考虑到您注意到这是一个非常大的应用程序?与ADO等非托管代码相比,转换和使用.net sql提供程序对象会更有利

当然,问题是您有一个大型应用程序,我不太确定从遗留ADO转换(移开)是否切实可行

因此,很大一部分原因可能是由于ADO是非托管代码,它将与本机(而且非常酷的.net CLR优化器)进行彻底的斗争,在大多数情况下,这些优化器可以在性能方面做得相当好。然而,.net代码优化器只在.net“托管”代码上工作,而不是像以前那样在非托管代码库上工作

现在,我可以将上面的代码作为ODBC进行尝试,也可以作为oleDB提供程序进行尝试(我打赌它们的性能都将与我上面使用的sqlProvider类似)

您也可以尝试将项目强制为x64,但我不确定x64位ADO提供程序是否可用

那么,现在和目前为止?我认为这个问题很大程度上是由于使用了未管理的ADO代码
Dim RecordSet As ADODB.RecordSet
RecordSet = New ADODB.Recordset
RecordSet.Open(sqladodbcommand, , , ADODB.LockTypeEnum.adLockOptimistic)
    Dim t As DateTime
    Debug.Print("start")

    t = Date.Now

    Using con As New SqlConnection(My.Settings.Test3)
        Dim strSQL As String = "SELECT * from tblHotels where ID  = @ID"
        Dim cmdSQL As New SqlCommand(strSQL, con)
        cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = 19
        con.Open()
        Dim rst As New DataTable
        For i = 1 To 10000
            rst.Clear()
            rst.Load(cmdSQL.ExecuteReader)
        Next

    End Using

    Debug.Print("time = " & ((Date.Now.Ticks - t.Ticks) / 10000000).ToString)
sql provider in .net (best choice)
oleDB provider in .net (a good choice when migration from VB6)

ODBC provider in .net (I like this if you ever want to swap database in future
and in fact ODBC is a better choice then say oleDB providers. And ODBC is making a
strong comeback in the marketplace with robust re-connection options for say SQL Azure