所以这种功能其实是必要的,并且很多情况是有用的。但是如果因为某些原因,在本来不需要使用的时候使用了这个功能,会导致原来很合理的执行计划被抛弃,选择不合理的执行计划,其结果就是查询运行好好的,但是突然变得奇慢无比。
总的来说,需要了解参数嗅探的本质,才能下定论。后续会专门写一个关于参数嗅探的文章,一旦发布会在本文中加入链接。
?
环境准备:
软件环境: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)——关键字查询