是存在即合理,我们应该具体情况具体分析。那么参数嗅探是什么呢?在执行计划缓存部分已经介绍了那个例子。在一些存储过程或者其他对象中,使用了传参数的方式,但是SQL Server并不知道你在实际执行时会传入什么参数,此时SQL Server就会使用一个预估值用于生成执行计划,但是在某些情况下,SQL Server也会“嗅探”实际传入的参数,并判断缓存中的执行计划针对当前语句及其参数是否不合理,是否有必要进行重编译。
所以这种功能其实是必要的,并且很多情况是有用的。但是如果因为某些原因,在本来不需要使用的时候使用了这个功能,会导致原来很合理的执行计划被抛弃,选择不合理的执行计划,其结果就是查询运行好好的,但是突然变得奇慢无比。
总的来说,需要了解参数嗅探的本质,才能下定论。后续会专门写一个关于参数嗅探的文章,一旦发布会在本文中加入链接。
?
环境准备:
软件环境:SQL Server 2008 R2,最好企业版。操作系统随意。
示例数据库:AdventureWorks 2008 R2,下载地址:http://msftdbprodsamples.codeplex.com/releases/view/59211
?
除了上面环境,还要在数据库中构建一个存储过程的模版,说是模版,其实就是后续演示过程中,在这个模版里面添加某些语句而已:
?
CREATE PROCEDURE sp_Get_orders
@salesorderid int = NULL,
@fromdate datetime = NULL,
@todate datetime = NULL,
@minprice money = NULL,
@maxprice money = NULL,
@custid nchar(5) = NULL,
@custname nvarchar(40) = NULL,
@prodid int = NULL,
@prodname nvarchar(40) = NULL,
@employeestrvarchar(MAX) = NULL,
@employeetblintlist_tbltype READONLYAS
SELECT o.SalesOrderID, o.OrderDate, od.UnitPrice, od.OrderQty,
c.CustomerID, per.FirstName as CustomerName,p.ProductID,
p.Name as ProductName, per.BusinessEntityID as EmpolyeeID
FROM Sales.SalesOrderHeader o
INNER JOIN Sales.SalesOrderDetail od ON o.SalesOrderID = od.SalesOrderID
INNER JOIN Sales.Customer c ON o.CustomerID = c.CustomerID
INNER JOIN Person.Person per on c.PersonID=per.BusinessEntityID
INNER JOIN Production.Product p ON p.ProductID = od.ProductID
WHERE ???
ORDER BY o.SalesOrderID
GO
?
注意上面WHERE ???的意思是后续例子中将会通过增减这个 WHERE条件并创建新命名的存储过程来演示。
简要说明一下存储过程的参数:
?
| @salesorderid |
订单ID |
| @fromdate |
起始日期 |
| @todate |
结束日期 |
| @minprice |
最低价 |
| @maxprice |
最高价 |
| @custid |
客户ID |
| @custname |
客户名 |
| @prodid |
产品ID |
| @prodname |
产品名 |
| @employeestr |
雇员ID的字符串组合,以逗号分割 |
| @employeetbl |
雇员ID的表值参数 |
?
?
?
如果用户不使用任何查询条件,那么查询条件将不起筛选作用,因此需要一个单纯的EXEC SP_GET_ORDERS的方式返回所有数据库订单的功能。
通过对存储过程的改写,可以应对业务中的下面需求:
?
用户可以选择如何对结果排序。依赖于输入的参数,语句可以访问不同的表或列。用户可以选择比较操作符,如@custname=’xxxx’或@custname !=’xxxx’。用户可以从输出结果中添加或移除列,也可以在聚合查询中选择聚合什么。其他你能想到甚至你不能想到但客户会想到的需求。
下一篇文章:T-SQL动态查询(2)——关键字查询