SQL Server OPTION (OPTIMIZE FOR UNKNOWN) 测试总结
关于SQL Server的查询提示OPTION (OPTIMIZE FOR UNKNOWN) ,它是解决参数嗅探的方法之一。 而且对应的SQL语句会缓存,不用每次都重编译。关键在于它的执行计划的准确度问题, 最近在优化的时候,和同事对于这个查询提示(Query Hint)有一点分歧,遂动手实验验证、总结了一些东西。
关于提示OPTION (OPTIMIZE FOR UNKNOWN),它会利用统计数据和标准算法生成一个折中、稳定的执行计划,但是它是无法利用直方图(histogram)信息来生成执行计划。官方文档的介绍如下:
OPTIMIZE FOR 编译和优化查询时提示查询优化器对本地变量使用特定值。仅在查询优化期间使用该值,在查询执行期间不使用该值。
UNKNOWN
指定查询优化器在查询优化期间使用统计数据而不是初始值来确定局部变量的值。OPTIMIZE FOR 可以抵消优化器的默认参数检测行为,也可在创建计划指南时使用
OPTIMIZE FOR UNKNOWN
指示查询优化器在查询已经过编译和优化时为所有局部变量使用统计数据而不是初始值,包括使用强制参数化创建的参数。有关强制参数化的详细信息,请参阅强制参数化。
如果在同一查询提示中使用 OPTIMIZE FOR @variable\_name = literal_constant 和 OPTIMIZE FOR UNKNOWN,则查询优化器将对特定的值使用指定的 literal_constant,而对其余变量使用 UNKNOWN。这些值仅用于查询优化期间,而不会用于查询执行期间。
OPTIMIZE FOR UNKNOWN是否会用直方图数据呢? 不会,OPTIMIZE FOR UNKNOWN只会用简单的统计数据。我们以how-optimize-for-unknown-works这篇博客中的例子来演示一下, 下面测试环境为SQL Server 2014,数据库为AdventureWorks2014
CREATE PROCEDURE test (@pid int)
AS
SELECT * FROM [Sales].[SalesOrderDetail]
WHERE ProductID = @pid OPTION (OPTIMIZE FOR UNKNOWN);
为了消除统计信息不准确会干扰测试结果,我们手工更新一下统计信息。
UPDATE STATISTICS [Sales].[SalesOrderDetail] WITH FULLSCAN;
我们在SSMS里面点击“包含实际执行计划”选项,然后测试执行该存储过程,如下截图所示: 执行计划居然走聚集索引扫描
EXEC test @pid=709

Filter里面过滤的记录为456.079,而实际上ProductID=709的记录有188条,那么优化器是怎么估计判断记录数为456.709的呢?


其实优化器是这样来估计的:它使用ProductID列的密度(Density)* Rows来计算的
SELECT 0.003759399 *121317 ~= 456.079008483 ~= 456.079
而ProductID列的密度(Density)的计算是这样来的:
ProductID的值有266个,可以用下面SQL获取ProductID的值个数
SELECT COUNT(DISTINCT ProductID) FROM Sales.SalesOrderDetail
SELECT 1.0/266 ~= 0.003759
然后你可以使用任意不同的参数测试,例如707、712......, 你会发现使用查询提示OPTION (OPTIMIZE FOR UNKNOWN)后,优化器会总是使用相同的执行计划。也就是说这个查询提示生成的执行计划是一个“折中的执行计划” ,对于数据分布倾斜的比较厉害(数据分布极度不均衡)的情况下,是极度不建议使用查询提示OPTION (OPTIMIZE FOR UNKNOWN)的。
本人曾经一度对使用OPTION(RECOMPILE)还是OPTION (OPTIMIZE FOR UNKNOWN)感到困惑和极度难以取舍,后面总结了一下:
1:执行不频繁的存储过程,使用OPTION(RECOMPILE)要优先与OPTION (OPTIMIZE FOR UNKNOWN)
2:执行频繁的存储过程,使用OPTION (OPTIMIZE FOR UNKNOWN)要优先于OPTION(RECOMPILE)
3:数据分布倾斜的厉害的情况下,优先使用OPTION(RECOMPILE)
4: 使用OPTION (OPTIMIZE FOR UNKNOWN)会生成一个稳定、统一的执行计划,如果这个执行计划的效率基本能满足用户需求,那么优先使用OPTION (OPTIMIZE FOR UNKNOWN)
参考资料:
https://docs.microsoft.com/zh-cn/previous-versions/sql/sql-server-2008/ms181714(v=sql.100)
http://www.benjaminnevarez.com/2010/06/how-optimize-for-unknown-works/
https://blogs.msdn.microsoft.com/sqlprogrammability/2008/11/26/optimize-for-unknown-a-little-known-sql-server-2008-feature/
SQL Server OPTION (OPTIMIZE FOR UNKNOWN) 测试总结的更多相关文章
- Top 10 steps to optimize data access in SQL Server
2009年04月28日 Top 10 steps to optimize data access in SQL Server: Part I (use indexing) 2009年06月01日 To ...
- .Net EF Core数据库使用SQL server 2008 R2分页报错How to avoid the “Incorrect syntax near 'OFFSET'. Invalid usage of the option NEXT in the FETCH statement.”
一. 问题说明 最近.Net EF core 程序部署到服务器,服务器数据库安装的是SQL server 2008 R2,我本地用的的是SQL server 2014,在用到分页查询时报错如下: H ...
- .NET Core EF框架使用SQL server 2008数据库分页问题:Incorrect syntax near 'OFFSET'. Invalid usage of the option NEXT in the FETCH statement
一. 问题 最近.Net Core程序部署到服务器,采用EF6.本地数据库是SQL server 2016,服务器数据库安装的是SQL server 2008 R2,在用到分页查询时报错如下: { & ...
- 谈一谈SQL Server中的执行计划缓存(下)
简介 在上篇文章中我们谈到了查询优化器和执行计划缓存的关系,以及其二者之间的冲突.本篇文章中,我们会主要阐述执行计划缓存常见的问题以及一些解决办法. 将执行缓存考虑在内时的流程 上篇文章中提到了查询优 ...
- SQL SERVER 中的提示
提示是指定的强制选项或策略,由 SQL Server 查询处理器针对 SELECT.INSERT.UPDATE 或 DELETE 语句执行. 提示将覆盖查询优化器可能为查询选择的任何执行计划. 注意: ...
- (转)SQL Server 性能调优(cpu)
摘自:http://www.cnblogs.com/Amaranthus/archive/2012/03/07/2383551.html 研究cpu压力工具 perfom SQL跟踪 性能视图 cpu ...
- SQL Server 2016的数据库范围内的配置
SQL Server 2016真的让人眼前一亮.几天前微软就提供了RCO(候选发布版)版本的下载.我已经围观了一圈RCO版本,其中一个最拽的功能是数据库范围内的配置(Database Scoped C ...
- 《Troubleshooting SQL Server》读书笔记-CPU使用率过高(下)
<Troubleshooting SQL Server>读书笔记-CPU使用率过高(下) 第三章 High CPU Utilization. CPU使用率过高的常见原因 查询优化器会尽量从 ...
- Microsoft SQL Server Trace Flags
Complete list of Microsoft SQL Server trace flags (585 trace flags) REMEMBER: Be extremely careful w ...
随机推荐
- Spring Boot SOAP Webservice例子
前言 本文将学习如何利用Spring boot快速创建SOAP webservice服务: 虽然目前REST和微服务越来越流行,但是SOAP在某些情况下,仍然有它的用武之地: 在本篇 spring b ...
- Java虚拟机监控命令
熟悉java的人都知道jdk的bin目录中有很多小工具,其中就包括用于监视虚拟机和故障处理的工具,今天就来仔细了解下各个工具的用法 jps JVM Process Status Tool,用于显示指定 ...
- File Explore 中data权限修改,实体机
如图: 1)root手机,360root 2)RootBrowser 改权限 3)ok
- Nginx里Header修改
有时候,我们可能有修改Nginx默认Header的需求.本文就将常见的方法列出来供大家参考. 修改普通请求的Header Nginx内置的模块暂时仅支持修改响应头,使用add_header.其中: a ...
- JavaScript和Ajax部分(3)
21. 原生(native)Ajax使用实例 //创建XMLHttpRequest对象的方法 function createXmlHttpRequest(){ if(window.ActiveXObj ...
- leetcode — search-insert-position
/** * Source : https://oj.leetcode.com/problems/search-insert-position/ * * Created by lverpeng on 2 ...
- vux环境配置
第一步 在vue项目中的package.json文件的dependencies中添加下面三行,即安装vux及其相关依赖 "vux":"^2.7.3", &quo ...
- 【ASP.NET MVC系列】浅谈ASP.NET 页面之间传值的几种方式
ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...
- Java 趣史-差点把 Java 命名成了 Silk(丝绸)
差点把 Java 命名成了 Silk(丝绸) Java 命名的由来 Java是印度尼西亚爪哇岛的英文名称,因盛产咖啡而闻名.Java语言中的许多库类名称,多与咖啡有关:如JavaBeans(咖啡豆). ...
- python函数的参数细节
按"指针"传递 python中变量赋值.参数传递都是通过"指针"拷贝的方式进行的.除了按"指针"拷贝,还有一种按值拷贝的方式,关于按值.按指 ...