2

当使用 SqlDataAdapter.fill() 运行存储过程时,我注意到在 Management Studio 中运行相同的存储过程只需要 1-2 秒,它需要超过 90 秒。我开始弄乱参数以试图找到问题,我最终做到了,尽管这是一个奇怪的问题。我发现如果我只是在sproc中声明了三个新变量,然后直接将参数的内容复制到其中,然后在sproc的主体中使用这些新变量,fill()方法下降到1-2秒,就像直接在管理工作室中运行存储过程。换句话说,这样做:

CREATE PROCEDURE [dbo].[TestProc]
    @location nvarchar(100), @startTime datetime, @endTime datetime
AS

declare @location2 nvarchar(100), @endTime2 datetime, @startTime2 datetime
set @location2 = @location
set @startTime2 = @startTime
set @endTime2 = @endTime

--... query using @location2, @startTime2, @endTime2

如果我将查询正文中的一个引用从@startTime2 更改回@startTime(从C# 传入的实际参数),则查询会立即跳回到大约90 秒甚至更长的时间。

所以....为什么 SQLDataAdapter 或 SQL Server 会关心我在将其参数传递到存储过程后如何处理它们?为什么这会影响执行时间?非常感谢任何有关如何进一步根除此问题的指导。谢谢!

编辑:虽然我可以发誓使用 SqlDataAdapter 从 C# 运行查询和使用管理工作室之间存在差异,但截至目前,我无法复制差异。现在,当我不复制参数时,管理工作室也需要 > 90 秒来运行存储过程。这是一个巨大的解脱,因为这意味着问题不在于 C#,而只是更多的运行(尽管仍然很奇怪)SQL Server 问题。我团队中的一个优秀的 SQL 人员正在查看存储过程的执行路径,无论是否首先复制参数。如果我们弄清楚了,我会在这里发布答案。感谢你目前的帮助!

4

1 回答 1

1

毫无疑问,这是一个参数嗅探和不当重用执行计划的案例,这些执行计划是使用具有非常不同的最佳访问模式的不同参数集创建的。

两种不同样式访问的突然变化相同(而不是一个快速)强烈表明缓存的执行计划已更新到现在使用两种访问方法执行缓慢的版本,或者您的数据或您的参数发生了变化。

以我的经验,这种小/巨大的执行时间差异的一般罪魁祸首是使用嵌套循环连接,其中实际上需要哈希匹配。(对于极少数的行,嵌套循环优于某个相当低的障碍,然后哈希匹配变得更便宜。除非您很幸运,您的输入都按连接条件排序,否则合并连接很少见查找,因为对大集合进行排序往往比散列匹配更昂贵。)

您在 SP 中调整参数解决问题的原因是,SQL Server 意识到您正在通过将参数设置为某个值(忽略您将它们设置为的值)来对参数执行某些操作,并且它必须计算新的执行计划,所以它抛弃了旧的,根据当前的一组参数设计了一个新的访问路径,得到了更好的结果。

如果这个问题仍然存在,那么使用 SP 重新编译/清除计划缓存以及使用必须处理大量不同行数的不同参数可能会揭示问题所在。查看用于以不同参数运行 SP 的执行计划,并查看在错误条件下采用不同访问策略的效果。

于 2012-02-06T00:46:26.010 回答