当须要根据外部输入的参数来决定要执行的SQL语句时,经常须要动态来构造SQL查询语句,我的以为用得比较多的地方就是分页存储过程和执行搜索查询的SQL语句。一个比较通用的分页存储过程,可能须要传入表名,字段,过滤条件,排序等参数,而对于搜索的话,可能要根据搜索条件判断来动态执行SQL语句。
在SQL Server中有两种方式来执行动态SQL语句,分别是exec和sp_executesql。sp_executesql相对而言具备更多的优势,它提供了输入输出接口,能够将输入输出变量直接传递到SQL语句中,而exec只能经过拼接的方式来实现。 还有一个优势就是sp_executesql,可以重用执行计划,这就大大提升了执行的性能。因此通常状况下建议选择sp_executesql来执行动态SQL语句。
使用sp_executesql须要注意的一点就是,它后面执行的SQL语句必须是Unicode编码的字符串,因此在声明存储动态SQL语句的变量时必须声明为nvarchar类型(若是不知道SQL语句有多长,能够直接用nvarchar(max)类型),不然在执行的时候会报“过程须要类型为 'ntext/nchar/nvarchar' 的参数 '@statement'”的错误,若是是使用sp_executesql直接执行SQL语句,则必须在前面加上大写字母N,以代表后面的字符串是使用Unicode类型编码的。
下面来看看几种动态执行SQL语句的状况
1.普通SQL语句
exec('select * from Student') exec sp_executesql N'select * from Student'--此处必定要加上N,不然会报错
2.带参数的SQL语句html
declare @sql nvarchar(1000) declare @userId varchar(100) set @userId='0001' set @sql='select * from Student where UserID='''+@userId+'''' exec(@sql)
declare @sql nvarchar(1000) declare @userId varchar(100) set @userId='0001' set @sql=N'select * from Student where UserID=@userId' exec sp_executesql @sql,N'@userId varchar(100)',@userId
从这个例子中能够看出使用sp_executesql能够直接将参数写在sql语句中,而exec须要使用拼接的方式,这在必定程度上能够防止SQL注入,所以sp_executesql拥有更高的安全性。另外须要注意的是,存储sql语句的变量必须声明为nvarchar类型的。sql
3.带输出参数的SQL语句安全
create procedure [dbo].[sp_GetNameByUserId] ( @userId varchar(100), @userName varchar(100) output ) as begin declare @sql nvarchar(1000) set @sql=N'select @userName=UserName from Student where UserId=@userId' exec sp_executesql @sql,N'@userId varchar(100),@userName varchar(100) output',@userId,@userName output select @userName end
原文连接性能