参数嗅探(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)。
-- Create a test table
CREATE TABLE Table1
(
Column1 INT IDENTITY,
Column2 INT
)
GO CREATE NONCLUSTERED INDEX idx_Test ON Table1(Column2) -- Insert 1500 records into Table1
INSERT INTO Table1 (Column2) VALUES (1) SELECT TOP 1499 IDENTITY(INT, 1, 1) AS n INTO #Nums
FROM
master.dbo.syscolumns sc1 INSERT INTO Table1 (Column2)
SELECT 2 FROM #nums
DROP TABLE #nums
GO
基于这个不平均的数据分布和临界点,对于同个逻辑查询会有2个不同的执行计划,点击工具栏的
显示包含实际的执行计划:
SELECT * FROM dbo.Table1 WHERE Column2=1
SELECT * FROM dbo.Table1 WHERE Column2=2

现在当你创建一个存储过程时,查询优化器会根据第一次提供的参数值生成执行计划,然后在接下来的执行中就会盲目重用了。
-- Create a new stored procedure for data retrieval
CREATE PROCEDURE RetrieveData
(
@Col2Value INT
)
AS
SELECT * FROM Table1
WHERE Column2 = @Col2Value
GO
SET STATISTICS IO ON
EXEC dbo.RetrieveData @Col2Value = 1 -- int
EXEC dbo.RetrieveData @Col2Value = 2 -- int


现在当你用1值运行存储过程时,只返回1条记录,查询优化器在执行计划里选择书签查找。查询只产生3个逻辑读。但是当你用2值运行存储过程时,缓存的计划被重用,书签查找反复执行1499次。每条记录上都执行!查询现在产生了1505个逻辑读。这和刚才的执行完全不同。当你看查看2值里执行计划里,SELECT运算符的属性时,在参数列表里你可以看到:
如你所见它们是不一样的,参数编译值是1,参数运行值是2。这就是说在你面前的执行都是基于参数值1而优化的,但实际上你传给存储过程的参数值是2。这就是SQL Server里的参数嗅探(Parameter Sniffing)问题。
小结
如你所见,在SQL Server里很容易碰到这个问题。每次你使用参数话的SQL查询(像在存储过程里),当表数据分布不平均,提供的非聚集索引没有覆盖到查询列时,你就会碰到这个问题。这里我们只介绍了这个问题,下篇文章我会向你展示如何处理这个问题,即SQL Server向你提供了哪些方案来解决这个问题。
参考文章:
https://www.sqlpassion.at/archive/2014/10/20/parameter-sniffing-part-1/
参数嗅探(Parameter Sniffing)(1/2)的更多相关文章
- 参数探测(Parameter Sniffing)影响存储过程执行效率解决方案
如果SQL query中有参数,SQL Server 会创建一个参数嗅探进程以提高执行性能.该计划通常是最好的并被保存以重复利用.只是偶尔,不会选择最优的执行计划而影响执行效率. SQL Server ...
- 何谓SQL Server参数嗅探
大家听到"嗅探"这个词应该会觉得跟黑客肯定有关系吧,使用工具嗅探一下参数,然后截获,脱裤o(∩_∩)o . 事实上,我觉得大家太敏感了,其实这篇文章跟数据库安全没有什么关系,实际上 ...
- 何谓SQLSERVER参数嗅探(转载)
大家听到“嗅探”这个词应该会觉得跟黑客肯定有关系吧,使用工具嗅探一下参数,然后截获,脱裤o(∩_∩)o .事实上,我觉得大家太敏感了,其实这篇文章跟数据库安全没有什么关系,实际上跟数据库性能调优有关相 ...
- SqlServer 查询的时候过滤条件有参数导致速度很慢的问题-参数嗅探
何谓SQLSERVER参数嗅探 大家听到“嗅探”这个词应该会觉得跟黑客肯定有关系吧,使用工具嗅探一下参数,然后截获,脱裤o(∩_∩)o . 事实上,我觉得大家太敏感了,其实这篇文章跟数据库安全没有什么 ...
- 参数嗅探(Parameter Sniffing)(2/2)
在参数嗅探(Parameter Sniffing)(1/2)里,我介绍了SQL Server里参数嗅探的基本概念和背后的问题.如你所见,当缓存的计划被SQL Server盲目重用时,会带来严重的性能问 ...
- 理解性能的奥秘——应用程序中慢,SSMS中快(4)——收集解决参数嗅探问题的信息
本文属于<理解性能的奥秘--应用程序中慢,SSMS中快>系列 接上文:理解性能的奥秘--应用程序中慢,SSMS中快(3)--不总是参数嗅探的错 前面已经提到过关于存储过程在SSMS中运行很 ...
- 理解性能的奥秘——应用程序中慢,SSMS中快(4)收集解决参数嗅探问题的信息
---从计划缓存中直接获取查询计划和参数: ), ) SELECT @dbname = 'hydee_连锁', @procname = 'dbo.p_select_ware'; WITH baseda ...
- 参数(parameter)和属性(Attribute)的区别
参数(parameter)和属性(Attribute)的区别 区别: 来源不同: 参数(parameter)是从客户端(浏览器)中由用户提供的,若是GET方法是从URL中 提供的,若是POST方法是从 ...
- 请求(Request)的参数(Parameter)里包含特殊字符(#等)的正确处理方式
遇到一个问题 在一个地址链接(URL)里使用 url?param1=val1¶m2=val2 的方式传递参数,结果在获取参数值时发现不是当初设定的值. 具体案例 以特殊字符井号(#)为 ...
随机推荐
- Speech两种使用方法
COM组件使用speech: public class Speach { private static Speach _Instance = null ; private SpeechLib.SpVo ...
- puppy-language
puppy language是一种解释型的结构化脚本语言. 项目地址: https://github.com/zlvb/PuppyLanguage 因为一直很忙,有段时间没去更新了,不过功能已经比较完 ...
- .NET通过async/await实现并行
如果可以并行可以大大提高性能,但在我们的使用中,不可能全是并行的也是要有线行操作,所以我们需要在业务逻辑层进行并行操作的护展: 数据访问层不变还是以前一样如下: public class UserDA ...
- Linux之date
近期学习需要根据不同的日期的数据,做同样的操作,如果一遍遍的手动操作,太笨重了,有些愚公的味道.所以就想着在shell下,将时间当做变量,然后重复其他的操作. 这里的需求是得到从某天(例如:2014- ...
- jqPlot插件绘制柱状图
每天都在这里看别人写的东西,确发现自己好久没写文章了,可能是因为确实很忙,或许这也是在给自己找的一种借口. 不过这也是我人生中加入得第一个创业公司,来到这里才知道创业公司其实真的很辛苦,产品的萌芽才开 ...
- java单例之enum实现方式
传统的两私有一公开(私有构造方法.私有静态实例(懒实例化/直接实例化).公开的静态获取方法)涉及线程安全问题(即使有多重检查锁也可以通过反射破坏单例), 目前最为安全的实现单例的方法是通过内部静态en ...
- 命令行模式下 MYSQL导入导出.sql文件的方法
一.MYSQL的命令行模式的设置:桌面->我的电脑->属性->环境变量->新建->PATH=“:path\mysql\bin;”其中path为MYSQL的安装路径.二.简 ...
- Maven3路程(六)用Maven创建Spring3 MVC项目
Maven3路程(六)用Maven创建Spring3 MVC项目 一. 环境 spring-framework-3.2.4.RELEASE jdk1.7.0_11 Maven3.0.5 ec ...
- nohup启动java命令导致dubbo无法注册
没有任何异常,日志和正常注册日志一模一样,但服务就是没注册成功. 解决办法,screen代替nohup命令. screen screen -ls screen -r pid (ctrl + a)+d
- SQL语句 - 数据操作
表中数据的变化牵一发而动全身,会同时导致到索引中数据的变化.因此如果查询语句不需要索引,就应该删除无用的索引以提高效率. 一.INSERT语句 1.基本插入语句 insert用于向表中输入数据,其具体 ...