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

我们的任务是将旧版VB6应用程序转换为VB.Net。

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

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

我们观察到,使用VB.NET版本进行测试需要花费更长的时间。

作为分析的一部分,我们创建了一个测试,该测试仅对应用程序使用ADODB访问SQL数据库的部分进行负载测试。

这是性能问题所在。

尤其是问题在于通过键从相对较小的表(例如20左右列)中检索单行。

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

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

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

Driver = {SQL Server};服务器= MYCOMPUTER \ SQLEXPRESS;数据库= THEDATABASENAME

用于检索的存储过程为:

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,则失败)。

Dim RecordSet As ADODB.RecordSet
Set RecordSet = sqladodbcommand.Execute

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

以下是用于执行单行检索的.NET代码(如果是测试类型3,则失败)。

Dim RecordSet As ADODB.RecordSet
RecordSet = New ADODB.Recordset
RecordSet.Open(sqladodbcommand,ADODB.LockTypeEnum.adLockOptimistic)

预期的问题:

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

任何见解或建议都会得到感谢。

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

但是,在检索方面,检索速度(至少)是VB6的两倍,并且比ADODB快一百倍。

(对于可能在搜索过程中阅读本书的任何新手,请查看System.Data.SqlClient中的接口。)

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

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

哼,问题在于ADO reocrdsets是非托管代码。结果,.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)

现在,我正在运行具有1.7 GHz i3(非常低端)的自卸式消防笔记本电脑。

我得到的时间超过了6.6428576秒,或者说是6642百万秒。

我猜想如果硬件更好,以上内容将再次下降一半。

现在,假设您已注意到这是一个非常大的应用程序?与非托管代码(例如ADO)相对,转换和使用.net sql提供程序对象将是一个优势。

当然,问题在于您有一个大型应用程序,但我并非所有人都认为从遗留ADO转换(移开)是否可行。

因此,其中很大一部分可能是由于ADO的非托管代码将与本机打交道(非常酷的.net CLR优化器在大多数情况下可以做得很好)性能。但是,.net代码优化器只能在.net“托管”代码上运行,而不是非托管代码库。

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

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

那么,现在和到目前为止?我认为这个问题很大程度上是由于在这里使用非托管ADO代码所致。我会说尝试与我发布的内容类似的测试存根。 (您的硬件要比上面测试过的我的垃圾箱budjet笔记本电脑更好)。

POSSILE迁移可以使用oleDB提供程序,因为这应该使语法保持相似,但是如上所述,我再次使用本机DataTable对象。 (如果您使用这些原生.net对象,例如datarow,datatable等,则它们100%相同

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

最后的选择是什么?好吧,那将使用对ADO旧式库的外部引用。

当某人从VB6转换到vb.net时,这里的问题真正开始了。那是应该发生的,并且远离ADO传统(不受管理)的迁移。

无论如何,请尝试上面的代码。我建议上面提到的所有3个.net提供程序都应执行类似的操作。并且请记住,以上操作是在运行1.7GHz的底部进纸器笔记本电脑上运行的。

本文链接:https://www.f2er.com/1402046.html

大家都在问