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

原文:参数嗅探(Parameter Sniffing)(2/2)

参数嗅探(Parameter Sniffing)(1/2)里,我介绍了SQL Server里参数嗅探的基本概念和背后的问题。如你所见,当缓存的计划被SQL Server盲目重用时,会带来严重的性能问题。今天我会向你展示下如何处理这个问题,即使用不同的技术克服它。

索引(Index)

上次我们讨论造成参数嗅探问题的根源是:在执行计划里,SQL 语句有时会产生书签查找,有时会产生表/聚集索引扫描。如果你能在数据库里修改索引,解决这个问题的最简单方法就是提供查询列对应的覆盖非聚集索引。这里我们就要包含书签查找的需要列,在非聚集索引的叶子层。这样做后,就可以获得计划稳定性:不管提供的输入任何参数,查询优化器都可以编译同样的执行计划——这里就是都会用到索引查找(非聚集索引)运算符。

1 DROP  INDEX idx_Test ON Table1
2 CREATE NONCLUSTERED INDEX idx_Test ON Table1(Column2) INCLUDE(Column1)
3
4 SELECT * FROM dbo.Table1 WHERE Column2=1
5 SELECT * FROM dbo.Table1 WHERE Column2=2

如果你不能修改你的索引设计,可以尝试下面的方法:

重编译(Recompilation)

SQL Server提供给你的第一个选项是执行计划的重编译。它提供2个不同选项给你使用:

  • 全部重编译,整个存储过程
  • 有问题的SQL语句重编译,即所谓的语句级别的重编译(从SQL Server 2005起可用)

我们通过实例详细讲解下这2个选项。下面的语句会对整个存储过程进行重编译:

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

当你执行这样的存储过程时,查询优化器在每次执行前都会重新编译存储过程。因此你得到的执行计划都是基于目前输入的参数值。作为重编译的副作用,你的执行计划不会被缓存,对于一个每次都重编译的执行计划进行缓存是没有意义的。当你有一个大的复杂的存储过程在存储过程级别使用RECOMPILE选项,这样做就没太大意义,因为你的整个存储每次都重编译,而存储过程就是为了编译好进行重用,从而提高执行效率。

1 EXEC dbo.RetrieveDataR @Col2Value = 1 -- int
2 EXEC dbo.RetrieveDataR @Col2Value = 2 -- int

如果你的参数嗅探问题只出现在一个特定的SQL语句。那就没有必要对整个存储过程进行重编译了。因此从SQL Server2005开始,提供称为语句级别的重编译(Statement Level Recompilation) 。你可以对需要重编译的SQL语句加上RECOMPILE查询提示而不是整个存储过程。我们来看下下面的代码:

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

上述例子里的第2个SQL语句在存储过程执行的时候都会重编译。第1个语句在执行初始时编译好,并生成计划缓存做后续重用。在你不想修改数据库的索引时,这个方法是处理参数嗅探的推荐方法。

1 EXEC dbo.RetrieveDataR2 @Col2Value = 2 -- int

 OPTIMIZE FOR

除了存储过程或SQL语句的重编译查询提示,SQL Server也提供OPTIMIZE FOR的查询提示。用这个查询提示你可以告诉查询优化器哪个参数值下,对执行计划执行优化,我们看下面的例子:

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

从存储过程的定义中你可以看到,SQL语句的执行计划在参数@Col2Value值为1的时候需要进行优化。不管你提供给这个参数的任何值,你都获得为值1优化的编译计划。用这个方法你已经对SQL Server放大招了,因为查询优化器没别的选项——它必须为参数值1生成优化的的执行计划。当你知道查询计划需要为指定参数进行优化时,可以使用这个方法让SQL Server对此参数的执行计划进行优化。在你重启SQL Server或执行群集故障转移时,就可以预知你的执行计划。

为了进一步保障这个选项的有效性,你就要熟悉你的数据分布情况,还有什么时候数据分布情况会改变。如果数据分布情况已经改变,你就要修改查询提示,看看是否仍然合适。你不能完全相信查询优化器,因为你已经用OPTIMIZE FOR查询提示重置查询优化器的选择。要记住这个。另外在提供OPTIMIZE FOR查询提示的同时,SQL Server也提供OPTIMIZE FOR UNKNOWN查询提示。如果你决定使用OPTIMIZE FOR UNKNOWN查询提示,查询优化器就使用表统计信息里的密度来做参数预估。如果逻辑读超过了临界点,还是会使用表/索引扫描…… 

小结

在这个文章里我向你展示在SQL Server里处理参数嗅探问题的不同方式。其中造成这个问题的最常见原因是糟糕的索引设计,造成参数值传入后优化器在执行计划里选择了书签查找。如果这样的执行计划被缓存重用的话,你的I/O成本就会爆表。在生成环境中,我就看到因为这个原因就造成100GB的逻辑读。在SQL语句上加一个简单的RECOMPILE查询提示就可以解决这个问题,查询只会增加少量的逻辑读。

如果你不能修改数据库索引设计,你可以在存储过程或SQL语句上使用RECOMPILE查询提示。作为副作用编译的计划就不会缓存。除此外的查询提示,SQL Server还提供OPTIMIZE FOROPTIMIZE FOR UNKNOWN的查询提示。在你使用这些查询提示时,你要对你的数据和数据分布情况非常熟悉,因为你在重置优化器。请慎重使用!Be always aware of this fact!

时间: 2024-11-12 05:50:47

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

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

原文:参数嗅探(Parameter Sniffing)(1/2) 这个问题会在参数话的SQL语句(例如存储过程)与SQL Server里的计划缓存机制结合的时候会出现.这个文章分为2个部分,第1部分会介绍下参数嗅探(Parameter Sniffing)的概况,第2部分我们介绍下如何解决这个问题. 什么是参数嗅探(Parameter Sniffing) 在SQL Server里当你执行参数话的SQL查询时,查询优化器会基于第一个提供的参数值编译执行计划.然后生成的执行计划在计划缓存里缓存作为后期

SQL Server Parameter Sniffing及其改进方法

上一篇我们谈到,SQL Server 在处理存储过程的时候,为了节省编译时间,是一次编译,多次重用.当第一次运行时代入值产生的执行计划,不适用后续代入的参数时,就产生了parameter sniffing问题. create procedure Sniff1(@i int) as SELECT count(b.SalesOrderID),sum(p.weight) from [Sales].[SalesOrderHeader] a inner join [Sales].[SalesOrderDe

SQL Server - 最佳实践 - 参数嗅探问题

title: SQL Server - 最佳实践 - 参数嗅探问题 author: 风移 摘要 MSSQL Server参数嗅探既是一个涉及知识面非常广泛,又是一个比较难于解决的课题,即使对于数据库老手也是一个比较头痛的问题.这篇文章从参数嗅探是什么,如何产生,表象是什么,会带来哪些问题,如何解决这五个方面来探讨参数嗅探的来龙去脉,期望能够将SQL Server参数嗅探问题理清楚,道明白. 什么参数嗅探 当SQL Server第一次执查询语句或存储过程(或者查询语句与存储过程被强制重新编译)的时

SQL Server · 最佳实践 · 参数嗅探问题

摘要 MSSQL Server参数嗅探既是一个涉及知识面非常广泛,又是一个比较难于解决的课题,即使对于数据库老手也是一个比较头痛的问题.这篇文章从参数嗅探是什么,如何产生,表象是什么,会带来哪些问题,如何解决这五个方面来探讨参数嗅探的来龙去脉,期望能够将SQL Server参数嗅探问题理清楚,道明白. 什么参数嗅探 当SQL Server第一次执行查询语句或存储过程(或者查询语句与存储过程被强制重新编译)的时候,SQL Server会有一个进程来评估传入的参数,并根据传入的参数生成对应的执行计划

ORACLE推导参数Derived Parameter介绍

Oracle的推导参数(Derived Parameters)其实是初始化参数的一种.推导参数值通常来自于其它参数的运算,依赖其它参数计算得出.官方文档关于推导参数(Derived Parameters)的概念如下:   Derived Parameters Some initialization parameters are derived, meaning that their values are calculated from the values of other parameters

Scala学习:叫名参数by-name parameter

上节展示的withPrintWriter方法不同于语言的内建控制结构,如if和while,在于大括号之间的代码 带了参数.withPrintWriter方法需要一个类型为PrintWriter的参数.这个参数以"writer =>"方 式显示出来: withPrintWriter(file) { writer => writer.println(new java.util.Date) } 然而如果你想要实现某些更像if或while的东西,根本没有值要传入大括号之间的代码,那

SQL 笔记 By 华仔

-------------------------------------读书笔记------------------------------- 笔记1-徐 最常用的几种备份方法 笔记2-徐 收缩数据库的大小的方法 笔记3-徐 设置数据库自动增长注意要点 笔记4-徐 模仿灾难发生时还原adventurework数据库 示例 stopat 笔记5-徐 检查日志文件不能被截断的原因 笔记6-徐 检测孤立用户并恢复孤立用户到新的服务器 解决数据库镜像孤立用户问题 笔记7-徐 SQLSERVER日志记录

SQLSERVER编译与重编译发生场景及重用的利弊介绍_MsSql

编译的含义 -------------------------------------------------------------------------------- 当SQLSERVER收到任何一个指令,包括查询(query).批处理(batch).存储过程.触发器(trigger) .预编译指令(prepared statement)和动态SQL语句(dynamic SQL Statement)要完成语法解释.语句解释, 然后再进行"编译(compile)",生成能够运行的&

sql server 编译与重编译详解

SQLSERVER编译与重编译 编译的含义 当SQLSERVER收到任何一个指令,包括查询(query).批处理(batch).存储过程.触发器(trigger) .预编译指令(prepared statement)和动态SQL语句(dynamic SQL Statement)要完成语法解释.语句解释, 然后再进行"编译(compile)",生成能够运行的"执行计划(execution plan)".在编译的过程中, SQLSERVER会根据所涉及的对象的架构(sc