几天前,我写了篇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里强制参数化的痛苦的更多相关文章

  1. SQL Server里简单参数化的痛苦

    在今天的文章里,我想谈下对于即席SQL语句(ad-hoc SQL statements),SQL Server使用的简单参数化(Simple Parameterization)的一些特性和副作用.首先 ...

  2. SQL Server里的闩锁介绍

    在今天的文章里我想谈下SQL Server使用的更高级的,轻量级的同步对象:闩锁(Latch).闩锁是SQL Server存储引擎使用轻量级同步对象,用来保护多线程访问内存内结构.文章的第1部分我会介 ...

  3. SQL Server里ORDER BY的歧义性

    在今天的文章里,我想谈下SQL Server里非常有争议和复杂的话题:ORDER BY子句的歧义性. 视图与ORDER BY 我们用一个非常简单的SELECT语句开始. -- A very simpl ...

  4. SQL Server里的自旋锁介绍

    在上一篇文章里我讨论了SQL Server里的闩锁.在文章的最后我给你简单介绍了下自旋锁(Spinlock).基于那个基础,今天我会继续讨论SQL Server中的自旋锁,还有给你展示下如何对它们进行 ...

  5. SQL Server里在文件组间如何移动数据?

    平常我不知道被问了几次这样的问题:“SQL  Server里在文件组间如何移动数据?“你意识到这个问题:你只有一个主文件组的默认配置,后来围观了“SQL Server里的文件和文件组”后,你知道,有多 ...

  6. SQL Server里的文件和文件组

    在今天的文章里,我想谈下SQL Server里非常重要的话题:SQL Server如何处理文件的文件组.当你用CREATE DATABASE命令创建一个简单的数据库时,SQL Server为你创建2个 ...

  7. 在SQL Server里我们为什么需要意向锁(Intent Locks)?

    在1年前,我写了篇在SQL Server里为什么我们需要更新锁.今天我想继续这个讨论,谈下SQL Server里的意向锁,还有为什么需要它们. SQL Server里的锁层级 当我讨论SQL Serv ...

  8. 在SQL Server里为什么我们需要更新锁

    今天我想讲解一个特别的问题,在我每次讲解SQL Server里的锁和阻塞(Locking & Blocking)都会碰到的问题:在SQL Server里,为什么我们需要更新锁?在我们讲解具体需 ...

  9. 在SQL Server里如何进行页级别的恢复

    在今天的文章里我想谈下每个DBA应该知道的一个重要话题:在SQL Server里如何进行页级别还原操作.假设在SQL Server里你有一个损坏的页,你要从最近的数据库备份只还原有问题的页,而不是还原 ...

随机推荐

  1. Aapache status / apache2ctl status 总是403

    默认apache2ctl status访问的是http://localhost:80/server_status 所以得搞定default这个站点,放歌html就可以了. 在default的配置里加入 ...

  2. Base: 一种 Acid 的替代方案

    原文链接: BASE: An Acid Alternative Pdf下载链接: Base 数据库 ACID,都不陌生:原子性.一致性.隔离性和持久性,这在单台服务器就能搞定的时代,很容易实现,但是到 ...

  3. 100+诡异的数据集,20万Eclipse Bug、死囚遗言等

    摘要:近日,Robert Seaton整理了100多个最有趣的数据集,其中包括Jeopardy真题,死囚的最后一句话,20万个Eclipse Bug,足球比赛相关,柏拉图式的爱情,太阳系以外的行星,1 ...

  4. Codeforces Round #382 (Div. 2) D. Taxes 哥德巴赫猜想

    D. Taxes 题目链接 http://codeforces.com/contest/735/problem/D 题面 Mr. Funt now lives in a country with a ...

  5. Git忽略配置文件gitignore

    在git客户端用户工程根目录下,.git同级目录创建文件.gitignore,文件名为.gitignore.目的是为了忽略一些不需要提交的文件到git服务器 配置如下: bin target .set ...

  6. HDU 4686 Arc of Dream (矩阵快速幂)

    Arc of Dream Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Tota ...

  7. SSH在Jenkins中的使用

    我们今天在迁移Jenkins的时候又出现无法调用私钥来获取oschina的git代码和使用scp拷贝无法验证的问题.我发现主要的问题实际上是关于ssh的问题,因为git和scp都是通过ssh来实现与远 ...

  8. 优先队列求解Huffman编码 c++

    优先队列小析      优先队列的模板: template <class T, class Container = vector<T>,class Compare = less< ...

  9. 2015.10.14-TransactionScope测试

    测试代码: ; ; List<string> lst = null; Action doSth = () => { using (var db = new TestSystemEnt ...

  10. HBase修改压缩格式及Snappy压缩实测分享

    一.要点 有关Snappy的相关介绍可参看Hadoop压缩-SNAPPY算法,如果想安装Snappy,可以参看Hadoop HBase 配置 安装 Snappy 终极教程. 1. HBase修改Tab ...