什么情况下会自动参数化
简单参数化模式下,对于有且只有一种执行方式的Adhoc SQL语句,SQL Server会自动参数化它,从而达到重用执行计划的目的。
究竟哪些类型的SQL会被自动参数化,后面会举例说明。 自动参数化会存在哪些问题
在简单模式下,SQL对于某些SQL会自动参数化他,避免每次都重编译。
SQL Server 自动参数化SQL语句的行为,能够避免一些重编译,原本也是出于“好意”,但是这种“好意”往往不一定总是给我们带来好处。
举例说明什么情况下会自动参数化
先造一个简单的测试环境
create table TestAuotParameter
(
id int not null,
col2 varchar(50)
)
GO
declare @i int=0
while @i<100000
begin
insert into TestAuotParameter values (@i, NEWID())
set @i=@i+1
end
GO
create unique index idx_id on TestAuotParameter(id)
GO
之所以自动参数化了SQL语句,就是因为select * from TestAuotParameter where id=33333 (66666,99999)这句SQL语句,
在当前的数据量下和唯一索引的特点,决定了有且只有一种高效的执行方式(也就是索引查找)
这里说有且只有一种方式是表中数据量相对较多,又因为idx_id这个索引是unique的。如果不是unique的,那么情况就不同了
如下查询条件:
1,初始查询条件为:CreateDate>'2016-6-1' and CreateDate<'2016-6-2',观察执行计划,实际行数是37903,预估行数为37117,预估还算准确
2,将查询条件更新为:CreateDate>'2016-6-1' and CreateDate<'2016-6-5',观察执行计划,实际行数为150706,预估行数不变,还是37117
3,将查询条件更新为:CreateDate>'2016-6-1' and CreateDate<'2016-6-9',观察执行计划,实际行数为302114,预估行数不变,还是37117
,
发现没有,因为查询时间段有变化,实际行数也有变化,但是不管实际行数多少,预估行数总是为第一次执行预估的行数。
这肯定不对吧?随便带入什么条件,预估行数都是37117,当时一下子蒙了,怎么每次执行SQL对数据行的预估都是一样的?
其实这个问题跟一开始举例的一样,都是SQL语句被自动参数化了,因此造成了执行计划重用,
执行计划重用,导致错误地预估实际查询的数据行数。
如何解决自动参数化造成错误地重用执行计划的问题
很多问题找到了真正的原因,解决起来往往并不难,这个问题的原因是执行计划重用造成的,那么我们只需要解决执行计划重用的问题即可
也就是不让他重用执行计划,只需要在SQL语句中加一个提示即可,
也即:select COUNT(1) from Test20160810 where CreateDate>'2016-6-1' and CreateDate<'2016-6-9' OPTION(RECOMPILE)
原因就在于加上OPTION(RECOMPILE)这个查询提示之后,不缓存SQL的执行计划缓存,没有了执行计划缓存,也就没得重用了
比如这个查询,在查询语句中加入OPTION(RECOMPILE)查询提示,让其执行之前重编译SQL语句,他就可以正确地预估数据行了。