SQL Server里强制参数化的痛苦
几天前,我写了篇SQL Server里简单参数化的痛苦。今天我想继续这个话题,谈下SQL Server里强制参数化(Forced Parameterization)。
强制参数化(Forced Parameterization)
在SQL Server里简单参数化有很多限制,如果你的SQL语句包含下列任意它不会发生:
- JOIN
- IN
- BULK INSERT
- UNION
- INTO
- DISTINCT
- TOP
- GROUP BY
- HAVING
- COMPUTE
- Sub Queries
如果你还想让SQL Server进行自动参数化,你可以启用在数据库层启用强制参数化:
-- Let's now activate Forced Parameterization on the AdventureWorks2012 database
ALTER DATABASE AdventureWorks2012 SET PARAMETERIZATION FORCED
GO
在这个情况下,SQL Server总会自动参数化你的SQL语句除掉以下情况:
- INSERT … EXECUTE
- Prepared SQL Statements
- RECOMPILE
- COMPUTE
为什么强制参数化总不是个好选择
现在让我们看下SQL Server里的强制参数化。对于AdventureWorks2012数据库,最后的代码已经将它启用强制参数化了。下一步我创建Sales.SalesOrderHeader表的副本,并将数据修正,这样的话在CustomerID列我们会有非线性的数据分布。另外我在那一列也创建了非聚集索引。
-- Create a copy from the Sales.SalesOrderHeader table
SELECT * INTO Sales.SalesOrderHeader2 FROM Sales.SalesOrderHeader
GO -- Create a Non-Clustered Index on the CustomerID column
CREATE NONCLUSTERED INDEX idx_CustomerID ON Sales.SalesOrderHeader2(CustomerID)
GO -- "Patch" the data in some way, so that the content of the column "CustomerID" is not evenly distributed across the whole table
UPDATE Sales.SalesOrderHeader2
SET CustomerID = 29675
WHERE SalesOrderID < 60000
GO
从下图你可以看到:ID为29675的客户有大量的订单,其它客户只有一些订单:
SELECT CustomerID,COUNT(SalesOrderID) SaleCount FROM Sales.SalesOrderHeader2
GROUP BY CustomerID ORDER BY 2 DESC

在下一步里我执行一个返回CustomerID为22943的所有记录——只有3条记录。因为查询在临界点前,SQL Server选择了有书签查找的执行计划。查询合计生成了3个逻辑读。因为我们对AdventureWorks2012数据库启用了强制参数化,对这个语句SQL Server也会自动参数化,因此执行计划会被后续的查询重用。
-- 3 Logical Reads
SELECT * FROM Sales.SalesOrderHeader2
WHERE CustomerID = 22943 -- Index Seek, returns 1 record
GO

我们再来运行另一个查询,返回所有CustomerID为29675的记录。在这个情况下查询返回16343条记录。当你再次看执行计划时,你会看到查询重用了刚才查询的执行计划。
SELECT * FROM Sales.SalesOrderHeader2
WHERE CustomerID = 29675
GO

这是对的,以为查询自动参数化,SQL Server在计划缓存里找已经缓存的计划。但是重用执行计划并不安全,因为现在我们进行了书签查找16343次——对每一行——反复执行。查询合计生成了16415个逻辑读。使用表扫描的话只要780个逻辑读。
这是强制参数化的副作用。SQL Server不管你执行计划的稳定性。SQL Server值自动参数化你的SQL语句,并反复重用缓存的执行计划。不管这个执行计划有糟糕。因为这是你强制SQL Server只要做的!没有启用强制参数化,SQL Server从不为你自动参数化SQL语句,因为那不安全。
性能问题的根源肯定是强制参数化。这里的根源是你的执行计划包含书签查找。因为书签查找你就没有计划稳定性。计划没有稳定性是说基于你输入参数值你会有不同的执行计划。在这个例子里有时你得到书签查找(临界点前),有时是表扫描(临界点后)。
在这个情况下,如果你修改下你的索引设计,为这个查询定义一个覆盖非聚集索引,性能问题也会消失。这样的话也不需要启用强制参数化,因为使用计划稳定性SQL Server会自动参数化你的SQL语句!
小结
在数据库级别启用强制参数化是个非常危险的事。不管你是否有计划稳定性,SQL Server总会自动参数化你的SQL语句,并反复重用你的执行计划。因此你要知道你的执行计划的详细情况,看看它们是否会引起性能相关的问题。
感谢关注!
参考文章:
https://www.sqlpassion.at/archive/2015/07/27/the-pain-of-forced-parameterization-in-sql-server/
SQL Server里强制参数化的痛苦的更多相关文章
- SQL Server里简单参数化的痛苦
在今天的文章里,我想谈下对于即席SQL语句(ad-hoc SQL statements),SQL Server使用的简单参数化(Simple Parameterization)的一些特性和副作用.首先 ...
- SQL Server里的闩锁介绍
在今天的文章里我想谈下SQL Server使用的更高级的,轻量级的同步对象:闩锁(Latch).闩锁是SQL Server存储引擎使用轻量级同步对象,用来保护多线程访问内存内结构.文章的第1部分我会介 ...
- SQL Server里ORDER BY的歧义性
在今天的文章里,我想谈下SQL Server里非常有争议和复杂的话题:ORDER BY子句的歧义性. 视图与ORDER BY 我们用一个非常简单的SELECT语句开始. -- A very simpl ...
- SQL Server里的自旋锁介绍
在上一篇文章里我讨论了SQL Server里的闩锁.在文章的最后我给你简单介绍了下自旋锁(Spinlock).基于那个基础,今天我会继续讨论SQL Server中的自旋锁,还有给你展示下如何对它们进行 ...
- SQL Server里在文件组间如何移动数据?
平常我不知道被问了几次这样的问题:“SQL Server里在文件组间如何移动数据?“你意识到这个问题:你只有一个主文件组的默认配置,后来围观了“SQL Server里的文件和文件组”后,你知道,有多 ...
- SQL Server里的文件和文件组
在今天的文章里,我想谈下SQL Server里非常重要的话题:SQL Server如何处理文件的文件组.当你用CREATE DATABASE命令创建一个简单的数据库时,SQL Server为你创建2个 ...
- 在SQL Server里我们为什么需要意向锁(Intent Locks)?
在1年前,我写了篇在SQL Server里为什么我们需要更新锁.今天我想继续这个讨论,谈下SQL Server里的意向锁,还有为什么需要它们. SQL Server里的锁层级 当我讨论SQL Serv ...
- 在SQL Server里为什么我们需要更新锁
今天我想讲解一个特别的问题,在我每次讲解SQL Server里的锁和阻塞(Locking & Blocking)都会碰到的问题:在SQL Server里,为什么我们需要更新锁?在我们讲解具体需 ...
- 在SQL Server里如何进行页级别的恢复
在今天的文章里我想谈下每个DBA应该知道的一个重要话题:在SQL Server里如何进行页级别还原操作.假设在SQL Server里你有一个损坏的页,你要从最近的数据库备份只还原有问题的页,而不是还原 ...
随机推荐
- ASSIC码对照表
编码对应字符: ✔:\u2714✘:\u2718 <script type="text/javascript"> var aaa = "\u2718" ...
- activemq安装和启动
安装环境:linux redhat activemq版本:5.8.0 1.从http://activemq.apache.org/download.html地址下载apache-activemq-5. ...
- 10条现代EQ技术基础贴士(转)
前言: 无论是追求复古的模拟音色还是高精度的透明音质,现代电脑音乐制作中层出不断的新EQ插件以其超强的频率塑形和个性化功能为音色的润色和重塑提供了无限可能. 虽然EQ并不是音频工程工具中最复杂的,但是 ...
- 利用 Python 只连接一次 MySQL
Github 地址 项目背景 最近做个项目,需要进行试驾分析,所谓"试驾",是指顾客在 4S 店指定人员的陪同下,沿着指定的路线驾驶车辆,从而了解这款汽车的行驶性能和操控性能.通常 ...
- Scala 深入浅出实战经典 第39讲:ListBuffer、ArrayBuffer、Queue、Stack操作代码实战
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- ubuntu 休眠之后网络间接失败 can not connect to network after suspend (wake up)
ubuntu for laptop系统在系统休眠后wakeup 之后,网络连接失败, 有线网络无法连接, 无线wifi无法连接, 只能重启后才能恢复, 此时可以采用以下方法处理: 1. 在/etc/p ...
- mac下忘记mysql密码, 重新设置mysql密码
step1: 苹果->系统偏好设置->最下边点mysql 在弹出页面中 关闭mysql服务(点击stop mysql server)step2:进入终端输入:cd /usr/local/m ...
- oracle小数点前零丢失的问题
1.问题起源 oracle 数据库 字段值为小于1的小数时,使用char类型处理,会丢失小数点前面的0 例如0.2就变成了.2 2.解决办法: (1)用to_char函数 ...
- 解决yum错误:Cannot retrieve repository metadata (repomd.xml) for repository
解决方法如下: # cd /etc/ #ls 找到yum.repos.d这个目录,里面有个文件CentOS-Media.repo(你的机器里也许不是这个名字,名称应该是自定义的),vi 编译一下里面的 ...
- Android复制assets目录下的图片到内存
转自:http://www.chenwg.com/android/android%E5%A4%8D%E5%88%B6assets%E7%9B%AE%E5%BD%95%E4%B8%8B%E7%9A%84 ...