sp_executesql命令在SQL Server中引入的比EXEC命令晚一些,它主要为重用执行计划提供更好的支持。
为了和EXEC作一个鲜明的对比,我们看看如果用代码1的代码,把EXEC换成sp_executesql,看看是否得到我们所期望的结果
DECLARE @TableName VARCHAR(50),@sql NVARCHAR(MAX),@OrderID INT ,@sql2 NVARCHAR(MAX);
SET @TableName = 'Orders ';
SET @OrderID = 10251;
SET @sql = 'SELECT * FROM '+QUOTENAME(@TableName) +
' WHERE OrderID = '+CAST(@OrderID AS VARCHAR(50)) + ' ORDER BY ORDERID DESC'
EXEC sp_executesql @sql
注意最后一行;
事实证明可以运行;
sp_executesql提供接口
sp_executesql命令比EXEC命令更灵活,因为它提供一个接口,该接口及支持输入参数也支持输出参数。这功能使你可以创建带参数的查询字符串,这样就可以比EXEC更好的重用执行计划,sp_executesql的构成与存储过程非常相似,不同之处在于你是动态构建代码。它的构成包括:代码快,参数声明部分,参数赋值部分。说了这么多,还是看看它的语法吧
EXEC sp_executesql
@stmt = <statement>,--类似存储过程主体
@params = <params>, --类似存储过程参数部分
<params assignment> --类似存储过程调用
@stmt参数是输入的动态批处理,它可以引入输入参数或输出参数,和存储过程的主体语句一样,只不过它是动态的,而存储过程是静态的,不过你也可以在存储过程中使用sp_executesql;
@params参数与定义输入/输出参数的存储过程头类似,实际上和存储过程头的语法完全一样;
@<params assignment> 与调用存储过程的EXEC部分类似。
为了说明sp_executesql对执行计划的管理优于EXEC,我将使用前面讨论EXEC时用到的代码。
1: DECLARE @TableName VARCHAR(50),@sql NVARCHAR(MAX),@OrderID INT;
2: SET @TableName = 'Orders ';
3: SET @OrderID = 10251;
4: SET @sql = 'SELECT * FROM '+QUOTENAME(@TableName) +
' WHERE OrderID = @OID ORDER BY ORDERID DESC'
5: EXEC sp_executesql
6: @stmt = @sql,
7: @params = N'@OID AS INT ',
8: @OID = @OrderID
在调用该代码和检查它生成的执行计划前,先清空缓存中的执行计划;
DBCC FREEPROCCACHE
将上面的动态代码执行3次,每次执行都赋予@OrderID 不同的值,然后查询sys.syscacheobjects表,并注意它的输出,优化器只创建了一个备用计划,而且该计划被重用的3次
SELECT cacheobjtype,objtype,usecounts,sql FROM sys.syscacheobjects
WHERE sql NOT LIKE '%cache%'
AND sql NOT LIKE '%sys.%' AND sql NOT LIKE '%sp_executesql%'