【问题标题】:Why are my database Commands always calling sp_describe_first_result_set?为什么我的数据库命令总是调用 sp_describe_first_result_set?
【发布时间】:2021-09-01 09:09:59
【问题描述】:

背景

我正在维护一个将记录导出到平面文件的 VB.Net(以前称为 VB6)实用程序。我们的一位客户报告说新版本需要很长时间才能运行,并且挖掘跟踪很容易看出原因:(我稍微混淆了这一点)

exec [sys].sp_describe_first_result_set 
N'Update [MAIN].[dbo].[Inventory] Set ExportId = @P1 Where Comp = @P2 and Osite = @P3 and Key = @P4',
N'@P1 numeric(10),@P2 varchar(6),@P3 varchar(6),@P4 int',1

这个和类似的语句每个都需要半秒钟。该实用程序必须使用有关导出的一些信息更新主库存表,并且该表被严重触发,因此sp_describe_first_result_set 必须模拟所有触发器以确定结果 - 我可以稍后在跟踪中验证这一点。

问题

我无法弄清楚为什么我的代码会调用 sp_describe_first_result_set 来获取更新语句,而这个语句甚至没有结果集。命令设置看起来并没有做任何奇怪的事情:

Dim connection = New ADODB.Connection
connection.ConnectionString = config.AdoConnectionString
connection.CursorLocation = CursorLocationEnum.adUseClient
connection.Open()

cmd = New ADODB.Command
With cmd
  .ActiveConnection = connection
  .CommandType = CommandTypeEnum.adCmdText
  .CommandText = "Update [MAIN].[dbo].[Inventory] " &
                 "Set ExportId = ? " &
                 "Where Comp = ? and Osite = ? and Key = ?"
  .Parameters.Append(NumericParameter(cmd.CreateParameter("ExportId", DataTypeEnum.adNumeric, ParameterDirectionEnum.adParamInput), 10, 0))
  .Parameters.Append(cmd.CreateParameter("Comp", DataTypeEnum.adVarChar, ParameterDirectionEnum.adParamInput, 6))
  .Parameters.Append(cmd.CreateParameter("Osite", DataTypeEnum.adVarChar, ParameterDirectionEnum.adParamInput, 6))
  .Parameters.Append(cmd.CreateParameter("Key", DataTypeEnum.adInteger, ParameterDirectionEnum.adParamInput))
End With

cmd.Parameters("ExportID").Value = lExportId
cmd.Parameters("Comp").Value = sComp
cmd.Parameters("Osite").Value = sOsite
cmd.Parameters("Key").Value = iKey
cmd.Execute()

是否有一些我只是想念的设置让它一直运行sp_describe_first_result_set?有没有办法阻止它这样做?

【问题讨论】:

  • 哇,ADODB,现在有一个“来自过去的爆炸”!自从我上次看到类似的东西以来,一定已经快 20 年了。
  • @CaiusJard 是的,这其中有一些棘手的逻辑,他们希望尽可能接近原始代码,尽管对于数据库访问,我认为这并不重要。年龄至少可以解释为什么我很难找到有关这方面的实际文档。

标签: vb.net adodb


【解决方案1】:

您需要明确表示您不需要记录集。

在 VB6 中,ADODB Command 对象可以根据 Execute() 函数的值是否被分配给任何东西来判断它是否应该返回记录集。

在 VB.NET 中,不再这样做,但可以将 execution options flags 作为参数提供给 Execute() 函数。像这样调用命令:

cmd.Parameters("ExportID").Value = lExportId
cmd.Parameters("Comp").Value = sComp
cmd.Parameters("Osite").Value = sOsite
cmd.Parameters("Key").Value = iKey
cmd.Execute(Options:=ExecuteOptionEnum.adExecuteNoRecords)

不会调用sp_describe_first_result_set来建立记录集的参数,只会直接执行命令,类似SqlCommand.ExecuteNonQuery()等更现代的方法。

【讨论】:

    【解决方案2】:

    出于好奇,与该代码等效的现代代码是否也跟踪执行此操作?

    Dim cmd as New SqlCommand( _
      "Update [MAIN].[dbo].[Inventory] Set ExportId = @e Where Comp = @c and Osite = @o and Key = @k", 
      "Data Source=YOUR_SERVER;Initial Catalog=YOUR_DB;User ID=YOUR_USER_EG_sa;Password=YOUR_PASSWORD" _
    )
    cmd.Connection.Open()
    cmd.Parameters.AddWithValue("@e", lExportId)
    cmd.Parameters.AddWithValue("@c", sComp)
    cmd.Parameters.AddWithValue("@o", sOsite)
    cmd.Parameters.AddWithValue("@k", iKey)
    cmd.ExecuteNonQuery()
    

    我在这里使用 AddWithValue 进行测试/方便,但您可能应该在 prod because it can cause performance issues with SQLS 中避免使用它 - 请参阅该链接以获取有关如何正确制作参数的建议

    【讨论】:

    • 不,现代版没有。我担心它也可能是数据库设置。
    • 事实证明,这是一个缺失的设置;我终于找到了一些相关的文档。谢谢你的努力,想。
    • 没有问题。请注意,在 SO 上说“谢谢,这个答案很有帮助/有用”的推荐方式是对其进行投票。另外不要忘记您可以将自己的答案标记为已接受,以便将仪表板上的问题外观更改为“已回答”。我敦促您也更新您的数据访问层,并且可能还看看 Dapper 以减少一些样板
    • 无法将我自己的答案标记为再接受 2 天。我想我是出于某些特权而赏金自己。
    • 哎呀,2天..我没有意识到它这么长!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-06
    • 2019-09-03
    • 1970-01-01
    • 2013-09-05
    • 1970-01-01
    • 1970-01-01
    • 2021-05-18
    相关资源
    最近更新 更多