sqlserver 中EXEC和sp_executesql使用介绍

sqlserver 中EXEC和sp_executesql使用介绍

MSSQL为我们提供了两种动态执行SQL语句的命令,分别是EXEC和sp_executesql;通常,sp_executesql则更具有优势,它提供了输入输出接口,而EXEC没有。还有一个最大的好处就是利用sp_executesql,能够重用执行计划,这就大大提供了执行性能(对于这个我在后面的例子中会详加说明),还可以编写更安全的代码。EXEC在某些情况下会更灵活。除非您有令人信服的理由使用EXEC,否侧尽量使用sp_executesql.

1、EXEC的使用

EXEC命令有两种用法,一种是执行一个存储过程,另一种是执行一个动态的批处理。以下所讲的都是第二种用法。

下面先使用EXEC演示一个例子,代码1

DECLARE @TableName VARCHAR(50),@SqlNVARCHAR(MAX),@OrderID INT;

SET @TableName = ‘Orders‘;

SET @OrderID = 10251;

SET @sql = ‘SELECT * FROM ‘+QUOTENAME(@TableName) +‘WHEREOrderID = ‘+CAST(@OrderID AS VARCHAR(10))+‘ ORDER BY ORDERID DESC‘

EXEC(@sql);

注:这里的EXEC括号中只允许包含一个字符串变量,但是可以串联多个变量,如果我们这样写EXEC:

EXEC(‘SELECT TOP(‘+
CAST(@TopCount
ASVARCHAR(10)) +‘)* FROM ‘+QUOTENAME(@TableName)+‘ ORDER BY ORDERID
DESC‘);

SQL编译器就会报错,编译不通过,而如果我们这样:

EXEC(@sql+@sql2+@sql3);

编译器就会通过;

所以最佳的做法是把代码构造到一个变量中,然后再把该变量作为EXEC命令的输入参数,这样就不会受限制了;

EXEC不提供接口

这里的接口是指,它不能执行一个包含一个带变量符的批处理,这里乍一听好像不明白,不要紧,我在下面有一个实例,您一看就知道什么意思.

DECLARE @TableName
VARCHAR(50),@Sql NVARCHAR(MAX),@OrderID
INT;

SET @TableName =
‘Orders‘;

SET @OrderID = 10251;

SET @sql =
‘SELECT * FROM ‘+QUOTENAME(@TableName)+‘WHERE
OrderID = @OrderID ORDER BY ORDERID DESC‘

EXEC(@sql);

关键就在SET @sql这一句话中,如果我们运行这个批处理,编译器就会产生一下错误

Msg 137, Level 15, State 2, Line 1必须声明标量变量 "@OrderID"。

使用EXEC时,如果您想访问变量,必须把变量内容串联到动态构建的代码字符串中,如:SET @sql= ‘SELECT * FROM ‘+QUOTENAME(@TableName) +‘WHERE OrderID = ‘+CAST(@OrderID AS VARCHAR(10))+‘ORDER BY ORDERID DESC‘

串联变量的内容也存在性能方面的弊端。SQL Server为每一个的查询字符串创建新的执行计划,即使查询模式相同也是这样。为演示这一点,先清空缓存中的执行计划

DBCC FREEPROCCACHE (这个不是本文所涉及的内容,您可以查看MS的MSDN)

http://msdn.microsoft.com/zh-cn/library/ms174283.aspx

将代码1运行3次,分别对@OrderID 赋予下面3个值,10251,10252,10253。然后使用下面的代码查询

SELECTcacheobjtype,objtype,usecounts,sqlFROM sys.syscacheobjects
WHEREsqlNOTLIKE‘%cach%‘ANDsqlNOTLIKE‘%sys.%‘

点击F5运行,就会出现下面如图所示的查询结果:

我们可以看到,每执行一次都要产生一次的编译,执行计划没有得到充分重用。

EXEC除了不支持动态批处理中的输入参数外,他也不支持输出参数。默认情况下,EXEC把查询的输出返回给调用者。例如下面代码返回Orders表中所有的记录数

DECLARE @sql NVARCHAR(MAX)

SET @sql =
‘SELECT COUNT(ORDERID) FROM Orders‘;

EXEC(@sql);

然而,如果你要把输出返回给调用批处理中的变量,事情就没有那么简单了。为此,你必须使用INSERT EXEC语法把输出插入到一个目标表中,然后从这表中获取值后赋给该变量,就像这样:

DECLARE @sql NVARCHAR(MAX),@RecordCount
INT

SET @sql =
‘SELECT COUNT(ORDERID) FROM Orders‘;

CREATETABLE #T(TID
INT);

INSERT
INTO #T EXEC(@sql);

SET @RecordCount = (SELECT TID
FROM #T)

SELECT @RecordCount

DROPTABLE #T

2、sp_executesql的使用

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
ASVARCHAR(50)) +
‘ ORDER BY ORDERIDDESC‘

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),@sqlNVARCHAR(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,sqlFROM sys.syscacheobjects WHERE sql NOT LIKE
‘%cache%‘ AND sql NOT LIKE
‘%sys.%‘ AND sql NOT LIKE
‘%sp_executesql%‘

点击F5运行,就会出现如下表所示的结果;

sq_executesql的另一个与其接口有关的强大功能是,你可以使用输出参数为调用批处理中的变量返回值。利用该功能可以避免用临时表返回数据,从而得到更高效的代码和更少的重新编译。定义和使用输出参数的语法与存储过程类似。也就是说,你需要在声明参数时指定OUTPUT子句。例如,下面的静态代码简单的演示了如何从动态批处理中利用输出参数@p把值返回到外部批处理中的变量@i.

DECLARE @sql AS NVARCHAR(12),@i AS INT;

SET @sql = N‘ SET @p = 10‘;

EXEC sp_executesql

@stmt = @sql,

@params = N‘@p AS INT OUTPUT‘,

@p= @i OUTPUT

SELECT @i

该代码返回输出10

时间: 2024-10-08 09:45:40

sqlserver 中EXEC和sp_executesql使用介绍的相关文章

【Sqlserver】T-SQL中EXEC 与 SP_EXECUTESQL的 区别

MSSQL为我们提供了两种动态执行SQL语句的命令,分别是 EXEC 和 SP_EXECUTESQL ,我们先来看一下两种方式的用法. 先建立一个表,并添加一些数据来进行演示: CREATE TABLE t_student( Id INT NOT NULL, Name NVARCHAR (10) NULL, Age TINYINT NULL, School NVARCHAR(20) NULL, Class NVARCHAR(10) NULL, Score FLOAT NULL, CONSTRAI

SQL Server 中 EXEC 与 SP_EXECUTESQL 的区别

原文:SQL Server 中 EXEC 与 SP_EXECUTESQL 的区别 MSSQL为我们提供了两种动态执行SQL语句的命令,分别是 EXEC 和 SP_EXECUTESQL ,我们先来看一下两种方式的用法. 先建立一个表,并添加一些数据来进行演示: CREATE TABLE t_student( Id INT NOT NULL, Name NVARCHAR (10) NULL, Age TINYINT NULL, School NVARCHAR(20) NULL, Class NVAR

SQLServer : EXEC和sp_executesql的区别

MSSQL为我们提供了两种动态执行SQL语句的命令,分别是EXEC和sp_executesql.通常,sp_executesql则更具有优势,它提供了输入输出接口,而EXEC没有.还有一个最大的好处就是利用sp_executesql,能够重用执行计划,这就大大提供了执行性能(对于这个我在后面的例子中会详加说明),还可以编写更安全的代码.EXEC在某些情况下会更灵活.除非您有令人信服的理由使用EXEC,否则尽量使用 sp_executesql. EXEC的使用 EXEC命令有两种用法,一种是执行一

SQLServer中的死锁的介绍

原文:SQLServer中的死锁的介绍 简介      什么是死锁? 我认为,死锁是由于两个对象在拥有一份资源的情况下申请另一份资源,而另一份资源恰好又是这两对象正持有的,导致两对象无法完成操作,且所持资源无法释放. 什么又是阻塞? 阻塞是由于资源不足引起的排队等待现象.比如同时两个进程去更新一个表. 这里我们可以把阻塞作为死锁的必要条件.下面我们先理解一下死锁和阻塞再来看一下我最近遇到一个问题以及解决思路. SQLServer中的死锁      对应到SQL Server中,当在两个或多个任务

[转]SQLServer : EXEC和sp_executesql的区别

MSSQL为我们提供了两种动态执行SQL语句的命令,分别是EXEC和sp_executesql.通常,sp_executesql则更具有优势,它提供了输入输出接口,而EXEC没有.还有一个最大的好处就是利用sp_executesql,能够重用执行计划,这就大大提供了执行性能(对于这个我在后面的例子中会详加说明),还可以编写更安全的代码.EXEC在某些情况下会更灵活.除非您有令人信服的理由使用EXEC,否则尽量使用 sp_executesql. EXEC的使用 EXEC命令有两种用法,一种是执行一

exec和sp_executesql

sqlserver中的exec和sp_executesql都能执行动态的sql语句和存储过程,但exec用法较为简单,不能带参数,也没有返回参数. sp_executesql则显得功能更加完善,可以用输入参数和输出参数,下面这个例子记录了sp_executesql的用法. declare @sql nvarchar(1000), @oazaName varchar(20), @cnt int set @oazaName = 'abc' set @sql = 'select @count=coun

exec vs sp_executesql

1.exec  vs  sp_executesql 1.1 说到exec了解SQLServer的朋友第一反应应该是它用来执行存储过程,对的这是其一,另一个作用是执行一个动态批处理.总结下:a.执行一个存储过程 b.执行一条sql语句. 1.2 sp_executesql SQL Server 2008 R2 联机丛书:执行可以多次重复使用或动态生成的 Transact-SQL 语句或批处理.Transact-SQL 语句或批处理可以包含嵌入参数. 2.二者比较 2.1.sp_executesql

(转)在SqlServer中,教你如何修改列名

通常,我们在使用SqlServer创建数据库中,在创建基本表时,偶尔会把表中的列名给起错了.想要把列名给改过来,一般有很多种改法,但是复杂程度却是不一样,有的人把整个表格删掉,重新建立来达到修改列名......通常花费大量的力气, 在这里,向大家介绍一种方法,直接一个语句就可搞定. 例如:我们已在数据库中建立了如下表 但是根据需要,想要把表中国的Ssex列名该为Sex,利用如下语句就OK: exec sp_rename 'student.Ssex','Sex','column'; 执行后就可达到

sqlserver中select造成死锁

项目上线,准备验收前出现了一个严重的问题:很多select语句作为死锁的牺牲,大部分报表无法打开.这个问题影响范围很大所有的报表都无法访问,而我们的报表是放在电视上面轮播的,电视放在工厂里面,所以出现问题后,整个工厂都知道了. 解决这个问题比较曲折,首先是写SAP接口的同事发现了问题:SAP一直在传错误数据导致产量表被锁住.修改SAP传输的错误数据后,这个死锁的问题没有出现了.但是我查看生产环境服务器日志的时候,发现这个问题依然存在,由于客户没有提这个问题,我也就是没有理由要求花时间修改了,因为