参数嗅探(Parameter Sniffing)(1/2)

这个问题会在参数话的SQL语句(例如存储过程)与SQL Server里的计划缓存机制结合的时候会出现。这个文章分为2个部分,第1部分会介绍下参数嗅探(Parameter Sniffing)的概况,第2部分我们介绍下如何解决这个问题。

什么是参数嗅探(Parameter Sniffing)

在SQL Server里当你执行参数话的SQL查询时,查询优化器会基于第一个提供的参数值编译执行计划。然后生成的执行计划在计划缓存里缓存作为后期的重用。这就是说SQL Server后续会直接重用这个计划,而不管每次你提供的不同参数值。我们需要识别2类参数值:

  • 参数编译值(Compile time values)
  • 参数运行值(Runtime values)

参数编译值是用于查询优化器生成物理执行计划的值。参数运行值是提供给执行计划运行的值。对于第一次执行这些值是一致的,但接下来的执行,这些值就很可能不同了。这就会带来严重的性能问题,因为执行计划只为编译值而优化的,不是为你接下来提供的不同运行值而优化。

如果你在第一次查询执行的时候提供了一个特定值,然后查询优化器选择了非聚集索引查找和书签查找运算符从你表里来获取所有查询列。这样的执行计划只对特定值有意义,非特定值的话,你的逻辑读数就会很高,SQL Server会选择全表扫描,忽略定义的非聚集索引。SQL Server选择这2个计划的决定点就是所谓的临界点(Tipping Point)

如果书签查找的计划被缓存,SQL Server就不会理会输入值,盲目重用缓存的计划。这个情况下SQL Server的保护机制就失效了,只从计划缓存里执行缓存的计划。作为副作用,你的IO成本(逻辑都)就会爆表,查询的性能就会非常糟糕。我们来演示下这个情况,下面的脚本会创建一个简单的表,在表的第2列有不平均的数据分布(就第1条值是1,剩下的1499条值都是2)。

 1 -- Create a test table
 2 CREATE TABLE Table1
 3 (
 4     Column1 INT IDENTITY,
 5     Column2 INT
 6 )
 7 GO
 8
 9 CREATE NONCLUSTERED INDEX idx_Test ON Table1(Column2)
10
11 -- Insert 1500 records into Table1
12 INSERT INTO Table1 (Column2) VALUES (1)
13
14 SELECT TOP 1499 IDENTITY(INT, 1, 1) AS n INTO #Nums
15 FROM
16 master.dbo.syscolumns sc1
17
18 INSERT INTO Table1 (Column2)
19 SELECT 2 FROM #nums
20 DROP TABLE #nums
21 GO

基于这个不平均的数据分布和临界点,对于同个逻辑查询会有2个不同的执行计划,点击工具栏的显示包含实际的执行计划:

1 SELECT * FROM dbo.Table1 WHERE Column2=1
2 SELECT * FROM dbo.Table1 WHERE Column2=2

现在当你创建一个存储过程时,查询优化器会根据第一次提供的参数值生成执行计划,然后在接下来的执行中就会盲目重用了。

1 -- Create a new stored procedure for data retrieval
2 CREATE PROCEDURE RetrieveData
3 (
4     @Col2Value INT
5 )
6 AS
7     SELECT * FROM Table1
8     WHERE Column2 = @Col2Value
9 GO

1 SET STATISTICS IO ON
2 EXEC dbo.RetrieveData @Col2Value = 1 -- int
3 EXEC dbo.RetrieveData @Col2Value = 2 -- int

现在当你用1值运行存储过程时,只返回1条记录,查询优化器在执行计划里选择书签查找。查询只产生3个逻辑读。但是当你用2值运行存储过程时,缓存的计划被重用,书签查找反复执行1499次。每条记录上都执行!查询现在产生了1505个逻辑读。这和刚才的执行完全不同。当你看查看2值里执行计划里,SELECT运算符的属性时,在参数列表里你可以看到:

如你所见它们是不一样的,参数编译值是1,参数运行值是2。这就是说在你面前的执行都是基于参数值1而优化的,但实际上你传给存储过程的参数值是2。这就是SQL Server里的参数嗅探(Parameter Sniffing)问题。

时间: 2024-11-05 15:52:41

参数嗅探(Parameter Sniffing)(1/2)的相关文章

(4.13)参数嗅探

1 --参数嗅探 Parameter Sniffing 2013-2-8 2 3 --当使用存储过程的时候,总是要使用到一些变量.变量有两种,一种 4 --是在存储过程的外面定义的.当调用存储过程的时候,必须要给他代入 5 --值.这种变量,SQL在编译的时候知道他的值是多少. 6 7 --例如: 8 USE [AdventureWorks] 9 GO 10 DROP PROC Sniff 11 GO 12 CREATE PROC Sniff(@i INT) 13 AS 14 SELECT CO

参数嗅探(Parameter Sniffing)(2/2)

在参数嗅探(Parameter Sniffing)(1/2)里,我介绍了SQL Server里参数嗅探的基本概念和背后的问题.如你所见,当缓存的计划被SQL Server盲目重用时,会带来严重的性能问题.今天我会向你展示下如何处理这个问题,即使用不同的技术克服它. 索引(Index) 上次我们讨论造成参数嗅探问题的根源是:在执行计划里,SQL 语句有时会产生书签查找,有时会产生表/聚集索引扫描.如果你能在数据库里修改索引,解决这个问题的最简单方法就是提供查询列对应的覆盖非聚集索引.这里我们就要包

参数探测(Parameter Sniffing)影响存储过程执行效率

如果SQL query中有参数,SQL Server 会创建一个参数嗅探进程以提高执行性能.该计划通常是最好的并被保存以重复利用.只是偶尔,不会选择最优的执行计划而影响执行效率. SQL Server尝试通过创建编译执行计划来优化你的存储过程的执行.通常是在第一次执行存储过程时候会生成并缓存查询执行计划.当SQL Server数据库引擎编译存储过程中侦测到有参数值传递进来的时候,会创建基于这些参数的执行计划.这种在编译存储过程中侦测参数值的方法,通常被称为"参数探测".有时参数探测会产

Sql Server Parameter Sniffing 和 optimize for 介绍

Parameter sniffing是Sql Server 创建存储过程的执行计划时,根据传入的参数进行预估生成执行计划的一个功能,通俗的说,就是根据第一个参数为stored procedure生成执行计划,但是Stored Procedure的第一个参数产生的执行计划并不一定是最优的,当后续传参时重用执行计划时,原有的执行计划无法高效响应本次查询,导致查询性能低效. 对于参数嗅探导致的问题,可以使用重新编辑stored procedure,或使用optimize for hint来避免. Op

理解性能的奥秘——应用程序中慢,SSMS中快(4)——收集解决参数嗅探问题的信息

本文属于<理解性能的奥秘--应用程序中慢,SSMS中快>系列 接上文:理解性能的奥秘--应用程序中慢,SSMS中快(3)--不总是参数嗅探的错 前面已经提到过关于存储过程在SSMS中运行很快,但在应用程序中运行很慢的可能原因:因为ARITHABORT的不同选项会导致不同的缓存词目,另外由于SQL Server使用了参数嗅探导致获得了不同的执行计划. 虽然已经说明了这个现象的原因,但是还没解释:如何定位和解决这个问题?到目前为止,大家都知道了如何快速处理,如果这个问题很紧急,可以直接使用: EX

请求(Request)的参数(Parameter)里包含特殊字符(#等)的正确处理方式

遇到一个问题 在一个地址链接(URL)里使用  url?param1=val1&param2=val2  的方式传递参数,结果在获取参数值时发现不是当初设定的值. 具体案例 以特殊字符井号(#)为例. 部分参数值丢了 JS里设置参数 window.location="some_web_project/xxx.jsp?param_key=abc#xyz"; Java中取参数值 Sting paramVal = request.getParameter("param_ke

SQL Server 查询优化(测试02)参数嗅探-执行计划选择

最近常看到"参数嗅探"这个词,看了几篇文章,于是就自己摸索做个测试来加深印象! 去官网下载了数据库:AdventureWorks2012 直接测试吧! 找几个熟悉的表关联起来,用ProductID作为条件找到两个ID返回行数相差较大的值. ProductID=870(4688行) ProductID=897(2行) [测试一] --先清空计划缓存 DBCC FREEPROCCACHE --执行前先打开计数器监控查看(分开执行以下查询) select sdh.SalesOrderID,s

PHPStorm2017去掉参数提示 parameter name hints

PHPStorm2017去掉参数提示 parameter name hints JetBrains 的各种语言的 IDE 都灰常灰常好用, 个个都是神器, PHPStorm 作为PHP开发的神器也不必多说了 今天升级到 PHPStorm 2017.1 发现增加了好些新功能, 有个默认开启的参数名和类型提示功能, 虽然功能挺强大的, 不过我用不着, 还是关掉的好, 有同样需求的同学可以看看 例子比较特殊这么看起来确实有点费眼睛的感觉还是关掉的好 配置面板中搜索 parameter name hin

理解性能的奥秘——应用程序中慢,SSMS中快(5)——案例:如何应对参数嗅探

本文属于<理解性能的奥秘--应用程序中慢,SSMS中快>系列 接上文:理解性能的奥秘--应用程序中慢,SSMS中快(4)--收集解决参数嗅探问题的信息 首先我们需要明白,参数嗅探本身不是问题,而是一个特性,避免SQL Server做出盲目的假设,从而产生次优查询计划.但是有些情况下,参数嗅探却会带来负面影响.通常有下面三种典型的情况: 查询使用的参数嗅探完全不合适.也就是说,查询计划对于这次执行是合适的,但是对于下一次执行就可能不合适. 应用程序中存在特定的调用模式,而且与其他大部分调用模式差