You need to enable JavaScript to run this app. 为什么我的数据库命令总是调用sp_describe_first_result_set?
优惠活动
大模型
产品
解决方案
定价
更多

为什么我的数据库命令总是调用sp_describe_first_result_set?

背景

我正在维护一个用于将记录导出到平面文件的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必须模拟所有触发器执行才能确定结果,这点我在后续跟踪中已经验证。

问题

我无法理解为什么代码会针对update语句调用sp_describe_first_result_set,毕竟update语句根本没有返回结果集。命令的配置看起来也没有异常:

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?有没有办法可以禁止该行为?

解决方案

根本原因

这个问题的触发根源是你设置了CursorLocation = CursorLocationEnum.adUseClient(客户端游标)。
当使用客户端游标时,ADODB的SQL Server驱动会默认对所有执行的语句做结果集元数据预检测,哪怕是UPDATE这类本身没有返回结果集的语句,也会调用sp_describe_first_result_set模拟执行语句,提前获取可能返回的结果集结构。你的表有大量触发器,模拟执行的成本极高,就出现了单语句耗时半秒的问题。

修复方案

你可以根据自己的业务场景选择以下任意一种方案:

  • 方案1:不需要使用客户端游标特性的前提下,直接把游标位置改为服务端游标
    把代码里的connection.CursorLocation = CursorLocationEnum.adUseClient替换为connection.CursorLocation = CursorLocationEnum.adUseServer,服务端游标不会触发结果集预检测逻辑,直接执行UPDATE语句即可。
  • 方案2:必须保留客户端游标时,在执行命令时添加adExecuteNoRecords参数,明确告知驱动当前语句没有返回结果集
    把最后一行的cmd.Execute()修改为:
    cmd.Execute RecordsAffected:=Nothing, Options:=CommandTypeEnum.adCmdText Or ExecuteOptionEnum.adExecuteNoRecords
    
    这个参数会让驱动跳过结果集元数据检测的步骤,不会再调用sp_describe_first_result_set。
  • 方案3:把UPDATE逻辑封装为无返回结果集的存储过程,调用时把CommandType设置为adCmdStoredProc,也可以规避预检测逻辑,性能优于直接执行动态SQL。
    修改完成后可以通过SQL Server Profiler再次跟踪确认,sp_describe_first_result_set的调用会直接消失,更新操作的耗时会恢复到正常水平。

内容的提问来源于stack exchange,提问作者Glazius

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.16 04:15:03