问题标签 [parameter-sniffing]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
sql - 在您使用 SQL Server 的职业生涯中的某个阶段,参数嗅探是否会突然出现并发起攻击?
今天,我又遇到了一个重大问题,似乎是 SQL Server 2005 中的参数嗅探。
我有一个查询将一些结果与已知的良好结果进行比较。我在结果和已知的好结果中添加了一个列,这样每个月,我都可以在两边加载一个新的月份结果,并且只比较当前月份。新列在聚集索引中排在第一位,因此新的月份将添加到末尾。
我在我的子句中添加了一个条件WHERE
- 这是代码生成的,所以它是一个字面常量:
WHERE DATA_DT_ID = 20081231
-- 这是多余的,因为所有 DATA_DT_ID 现在都是 20081231。
性能进入底池。从 7 秒比较大约 150 万行到 2 小时,但什么也没完成。在 SSMS 中运行生成的 SQL - 没有 SP。
我使用 SQL Server 已有 12 年了,自 10 月以来,我从未在此生产服务器上遇到过如此多的参数嗅探问题(构建版本 9.00.3068.00)。在每种情况下,这都不是因为它第一次运行时使用了不同的参数或表发生了变化。这是一个新表,它仅使用此参数运行或根本没有WHERE
子句。
而且,不,我没有 DBA 访问权限,而且他们没有给我足够的权限来查看执行计划。
以至于我不确定我是否能够将这个系统交给只有几年经验的 SQL Server 用户处理。
UPDATE事实证明,尽管统计数据声称是最新的,但运行 UPDATE STATISTICS WITH FULLSCAN 可以解决问题。
最终更新即使使用 WITH RECOMPILE 和 UPDATE STATISTICS 重新创建 SP,结果还是必须以不同的方式重写查询,以使用 NOT IN 而不是 LEFT JOIN 和 NULL 检查。
sql - T-SQL 流程设计和执行计划(UDF 参数嗅探?)
在 SQL Server 2005 上,我有一个复杂的多级分配过程,如下所示(伪 SQL):
WhereALLOCS
以直接分配为种子,然后BALANCES(@LVL_NUM)
基于ALLOCS
at @LVL_NUM
(可能是一些直接分配加上前一级别的一些 IN 分配),并且ALOCNS(@LVL_NUM)
基于BALANCES(@LVL_NUM)
并且ALOCN_SUMRY(@LVL_NUM)
仅基于ALOCNS(@LVL_NUM)
- 有很多配置表,这些配置表指示驱动程序将分配赶出去。
这被简化了,但实际上循环中有四五对这样的对,因为有多种逻辑无法一起处理(有些情况可以一起处理)。
其基本逻辑是在特定成本中心/产品线/等(即)中获取总金额,然后根据其在特定成本中心/产品线/等中的份额(即百分比份额)将BALANCES
其分配给另一个成本中心/产品线/等。ALLOCNS / ALLOCN_SUMRY
公制。
在记录OUT
保存IN
和SUMRY
.ALLOCN
是一个加号!)。(现有的系统是一个怪物 C/C++/MFC/ODBC 程序,它将所有数据读入海量数组和其他数据结构中,编写得非常糟糕。)
问题似乎是,当在循环中运行时,我似乎遇到了执行计划问题,因为随着ALLOCS
表格开始发生变化(并且一切都在变化,因为级别有不同的成本中心,所以配置被用来驱动ALLOCNS
正在改变)。我认为我最多有 99 个级别,但最低级别从 2、4、6 开始。似乎@LVL_NUM = 6
在 UDF 之外单独运行表现良好,但 UDF 表现不佳 - 可能是因为 UDF 有缓存计划或整体计划已经很糟糕了,因为在ALLOCS
前面的步骤中添加了@LVL_NUM IN (2, 4)
。
在开发早期,我设法在 30 分钟内完成了 30 个关卡,但现在我无法在 2 小时内完成前 3 个关卡。
我正在考虑在另一个 SP 中运行这两个插入并将其称为 WITH RECOMPILE,但很好奇这个 RECOMPILE 是否正确级联到 TVF UDF?任何其他建议也将不胜感激。
真实代码:
这是我的测试批次,最终将在单个 SP 中运行整个过程。您可以从注释掉的部分看到我也一直在使用临时表和表变量:
sql - SQL差的存储过程执行计划性能——参数嗅探
我有一个存储过程,它接受一个日期输入,如果没有传入任何值,则稍后将其设置为当前日期:
我遇到了问题,如果在首次编译存储过程时@MyDate
传入,NULL
则所有输入值(或其他)的性能总是很糟糕NULL
,如果在编译存储过程时传入日期/当前日期所有输入值(NULL
或其他)的性能都很好。
同样令人困惑的是,即使 @MyDate 使用的值实际上是 NULL
(而不是CURRENT_TIMESTAMP
由 IF 语句设置),生成的糟糕的执行计划也很糟糕
我发现禁用参数嗅探(通过欺骗参数)可以解决我的问题:
我知道这与参数嗅探有关,但是我看到的所有“参数嗅探变坏”的示例都涉及使用传入的非代表性参数编译存储过程,但是在这里我看到了执行计划对于 SQL 服务器可能认为参数可能在执行语句的点可能采用的所有可能的值是可怕的 -NULL
或CURRENT_TIMESTAMP
其他。
有没有人知道为什么会这样?
sql - SP 需要 15 分钟,但执行相同的查询时会在 1-2 分钟内返回结果
所以基本上我有这个相对较长的存储过程。基本的执行流程是将SELECTS INTO
一些数据放入用他#
签名声明的临时表中,然后在这些表中运行游标,生成一个“运行总计”到第三个临时表中,该表是使用创建的CREATE
. 然后这个生成的临时表与数据库中的其他表连接起来,在一些分组等之后生成结果。问题是这个 SP 一直运行良好,直到现在在 1-2 分钟内返回结果。现在突然需要 12-15 分钟。如果我从 SP 中提取查询并通过手动设置相同的参数在管理工作室中执行它,它会在 1-2 分钟内返回结果,但 SP 需要很长时间。知道会发生什么。我尝试生成 Query 和 SP 的实际执行计划,但由于光标而无法生成它。知道为什么 SP 需要这么长时间而查询不需要吗?
sql - 奇怪的 SQL 服务器报告与更新统计信息相关的性能问题
我使用报告服务获得了一份复杂的报告,该报告连接到一个 SQl 2005 数据库,并调用了一些存储过程和函数。它最初工作正常,但几个月后(数据增长),它遇到超时错误。
我创建了一些索引来提高性能,但奇怪的是它在创建索引后工作,但第二天又抛出了同样的错误。然后我尝试更新数据库上的统计信息,它再次工作(查询的运行时间提高了 10 倍)。但同样,它在第二天停止工作。
现在,临时解决方案是我每小时运行一次更新统计信息。但我找不到这种行为的合理解释。数据库不是很忙,一天不会更新很多数据。更新统计数据怎么能有这么大的不同?
sql - 有没有办法延迟编译存储过程的执行计划?
(乍一看,这可能看起来像是直接执行语句和从存储过程执行语句时的不同执行计划或为什么 SqlServer 优化器与参数如此混淆?,但我的实际问题有点不同)
好吧,这个让我难倒了几个小时。我这里的例子抽象得离谱,所以我怀疑是否可以在本地重新创建,但它为我的问题提供了上下文(另外,我正在运行 SQL Server 2005)。
我有一个存储过程,基本上有两个步骤,构建一个临时表,用很少的行填充它,然后查询一个非常大的表来连接该临时表。它有多个参数,但最相关的是一个datetime
“ @MinDate
.”。本质上:
如果我只是将其作为普通查询执行,通过声明@MinDate
为局部变量并运行它,它会生成一个执行速度非常快的最佳执行计划(首先加入#smallTable,然后在执行时只考虑来自 aGiantTable 的一小部分行其他操作)。似乎意识到#smallTable 很小,所以从它开始会很有效。这很好。
但是,如果我将其作为参数作为存储过程@MinDate
,则会产生完全低效的执行计划。(我每次都在重新编译它,所以这不是一个糟糕的缓存计划……至少,我当然希望不是)
但这就是奇怪的地方。如果我将 proc 更改为以下内容:
然后它给了我有效的计划!
所以我的理论是这样的:当作为普通查询(而不是存储过程)执行时,它会等待为昂贵的查询构造执行计划,直到最后一分钟,所以查询优化器知道#smallTable 很小并使用该信息给出有效的计划。
但是当作为存储过程执行时,它会一次创建整个执行计划,因此无法使用这些信息来优化计划。
但是为什么使用本地声明的变量会改变这一点?为什么会延迟执行计划的创建?真的是这样吗?如果是这样,即使不以这种方式使用局部变量,是否有办法强制延迟编译(如果这确实是这里发生的事情)?
更一般地说,是否有人知道何时为存储过程的每个步骤创建执行计划?谷歌搜索没有提供任何有用的信息,但我不认为我在寻找正确的东西。还是我的理论完全没有根据?
编辑:自从发布以来,我已经了解了参数嗅探,我认为这是导致执行计划过早编译的原因(除非存储过程确实一次编译),所以我的问题仍然存在——你能强制延迟吗?或者完全禁用嗅探?
select * from aGiantTable
这个问题是学术性的,因为我可以通过替换来强制执行更有效的计划
或者只是吸收它并掩盖参数,但这种不一致仍然让我很好奇。
tl;dnr
这是一个非常长的问题,所以简而言之:
完整的执行计划是在第一次调用存储过程时创建的,还是在执行时创建的?也就是说,如果一个存储过程由多个步骤组成,每个步骤的执行计划是在第一次调用该过程时创建的,还是仅在过去的步骤完成执行后创建(再次,第一次调用它)?
sql-server - 绕过 SQL Server 2005 中的缓存计划
有人可以解释为什么这有效。这里是风景。我有一个存储过程,它开始运行缓慢。然后我选择一个参数并声明一个变量来容纳它的值,并在 proc 中使用声明的变量而不是参数。然后proc将大大加快。
我认为这与缓存的计划和统计信息有关,但我不确定。统计数据是否会随着数据库的增长和变化而过时,以便缓存计划针对与数据当前状态不同的数据过去状态进行优化?
谢谢。
sql-server - 绕过 SQL Server 2005 中的参数嗅探
我看到有人建议将参数复制到局部变量,以避免在存储过程中嗅探参数。说你有
(我从http://www.sommarskog.se/query-plan-mysteries.html得到这个,但我需要更多细节才能完全理解它)。
但这实际上对查询计划缓存和查询计划优化器有什么影响?如果优化器确实没有对@fromdate_copy 做出任何假设,那么为什么它不会缓存最有可能是全表扫描的计划(因为它没有做出任何假设,它怎么会生成其他任何东西呢? )?
这种技术基本上就像“没有输入会运行良好,但也没有输入会运行得非常糟糕”吗?
performance - 奇怪的是,在 SQL Server 2008 中制作参数副本大大加快了 SP
当使用 SqlDataAdapter.fill() 运行存储过程时,我注意到在 Management Studio 中运行相同的存储过程只需要 1-2 秒,它需要超过 90 秒。我开始弄乱参数以试图找到问题,我最终做到了,尽管这是一个奇怪的问题。我发现如果我只是在sproc中声明了三个新变量,然后直接将参数的内容复制到其中,然后在sproc的主体中使用这些新变量,fill()方法下降到1-2秒,就像直接在管理工作室中运行存储过程。换句话说,这样做:
如果我将查询正文中的一个引用从@startTime2 更改回@startTime(从C# 传入的实际参数),则查询会立即跳回到大约90 秒甚至更长的时间。
所以....为什么 SQLDataAdapter 或 SQL Server 会关心我在将其参数传递到存储过程后如何处理它们?为什么这会影响执行时间?非常感谢任何有关如何进一步根除此问题的指导。谢谢!
编辑:虽然我可以发誓使用 SqlDataAdapter 从 C# 运行查询和使用管理工作室之间存在差异,但截至目前,我无法复制差异。现在,当我不复制参数时,管理工作室也需要 > 90 秒来运行存储过程。这是一个巨大的解脱,因为这意味着问题不在于 C#,而只是更多的运行(尽管仍然很奇怪)SQL Server 问题。我团队中的一个优秀的 SQL 人员正在查看存储过程的执行路径,无论是否首先复制参数。如果我们弄清楚了,我会在这里发布答案。感谢你目前的帮助!
sql-server - 您是否应该始终预料到由参数嗅探引起的问题?
使用sql server 2008,我有一个简单的存储过程,其内容是
在最近的一次代码审查中,DBA 说我应该“添加参数嗅探”,我认为这意味着我应该考虑参数嗅探。我过去从未这样做过,并且查询没有任何性能问题,所以我认为这是不必要的。
虽然我认为答案可能是用户偏好,但考虑参数嗅探是否是最佳实践?如果在小数据集上调用存储过程,不经常使用并且没有性能问题,是否有必要?
编辑
这是否仅适用于WHERE子句中使用的参数,或者例如,您是否可能需要考虑INSERT语句中的所有参数?