前言

之前我们已经讨论过动态SQL查询呢?这里为何再来探讨一番呢?因为其中还是存在一定问题,如标题所言,很多面试题也好或者有些博客也好都在说在执行动态SQL查询时sp_executesql的性能比exec好,但是事实真是如此?下面我们来一探究竟。

探讨sp_executesql和exec执行动态SQL查询性能

首先我们创建如下测试表。

CREATE TABLE dbo.TestDynamicSQL(Col1 INT PRIMARY KEY ,Col2 SMALLINT NOT NULL ,CreatedTime DATETIME DEFAULT GETDATE() ,OtherValue CHAR(10) DEFAULT 'Jeffcky')
GO

接着再来插入数据,如下:

INSERT  dbo.TestDynamicSQL( Col1,Col2)SELECT  number + 1 ,numberFROM    master..spt_valuesWHERE   type = 'P'ORDER BY number

最终查询为如下测试数据:

接下来我们执行如下两个SQL查询语句,执行4次。

SELECT  *
FROM    dbo.TestDynamicSQL
WHERE   Col2 = 3AND Col1 = 4
GOSELECT  *
FROM    dbo.TestDynamicSQL
WHERE   Col2 = 4AND Col1 = 5
GO

紧接着我们通过如下SQL语句来查询缓存计划。

SELECT  q.text ,cp.usecounts ,cp.objtype ,p.* ,q.* ,cp.plan_handle
FROM    sys.dm_exec_cached_plans cpCROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) pCROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) AS q
WHERE   cp.cacheobjtype = 'Compiled Plan'AND q.text LIKE '%dbo.TestDynamicSQL%'AND q.text NOT LIKE '%sys.dm_exec_cached_plans %'

由上图可知,我们看到存在两个查询计划且每个执行了4次,也就是说每一次查询都会重新生成一个新的计划。清除查询计划缓存,通过如下命令:

DBCC FREEPROCCACHE

我们继续往下走,我们接下来通过EXEC来执行动态SQL查询,如下,执行查询完毕后再来看看查询计划次数:

DECLARE @Col2 SMALLINT
DECLARE @Col1 INTSELECT  @Col2 = 11 ,@Col1 = 12DECLARE @SQL VARCHAR(1000)
SELECT  @SQL = 'select * from dbo.TestDynamicSQL
where Col2 = ' + CONVERT(VARCHAR(10), @Col2) + '
and Col1 = ' + CONVERT(VARCHAR(10), @Col1)EXEC (@SQL)
GODECLARE @Col2 SMALLINT
DECLARE @Col1 INTSELECT  @Col2 = 12 ,@Col1 = 13DECLARE @SQL VARCHAR(1000)
SELECT  @SQL = 'select * from dbo.TestDynamicSQL
where Col2 = ' + CONVERT(VARCHAR(10), @Col2) + '
and Col1 = ' + CONVERT(VARCHAR(10), @Col1)EXEC (@SQL)
GO

这个就不做过多解释,我们依然要清除查询计划缓存,我们再利用sp_executesql来查询,如下:

DECLARE @Col2 SMALLINT
DECLARE @Col1 INTSELECT  @Col2 = 23 ,@Col1 = 24DECLARE @SQL NVARCHAR(1000)
SELECT  @SQL = 'select * from dbo.TestDynamicSQL
where Col2 = ' + CONVERT(VARCHAR(10), @Col2) + '
and Col1 = ' + CONVERT(VARCHAR(10), @Col1)EXEC sp_executesql @SQL
GoDECLARE @Col2 SMALLINT
DECLARE @Col1 INTSELECT  @Col2 = 22 ,@Col1 = 23DECLARE @SQL NVARCHAR(1000)
SELECT  @SQL = 'select * from dbo.TestDynamicSQL
where Col2 = ' + CONVERT(VARCHAR(10), @Col2) + '
and Col1 = ' + CONVERT(VARCHAR(10), @Col1)EXEC sp_executesql @SQL
GO

对比exec执行动态SQL查询得到的结果是一模一样,正如我所演示的,我们有两个计划,每个执行次数为4。不是说sp_executesql执行动态SQL查询会重用计划缓存么,这是因为我们没有正确使用sp_executesql所以导致SQL引擎无法重用计划。

当参数值改变为语句是唯一变化时,可以使用sp_executesql代替存储过程多次执行Transact-SQL语句。 因为Transact-SQL语句本身保持不变,只有参数值发生变化,因此SQL Server查询优化器可能会重用为第一次执行生成的执行计划。

以下是正确参数化的查询方式,我们在字符串里面有一些变量,在执行的时候,我们通过其他变量传递值给它。

DECLARE @Col2 SMALLINT ,@Col1 INT
SELECT  @Col2 = 3 ,@Col1 = 4DECLARE @SQL NVARCHAR(1000)
SELECT  @SQL = 'select * from dbo.TestDynamicSQL
where Col2 = @InnerCol2 and Col1 = @InnerCol1' DECLARE @ParmDefinition NVARCHAR(500)
SET @ParmDefinition = N'@InnerCol2 smallint ,@InnerCol1 int'EXEC sp_executesql @SQL, @ParmDefinition, @InnerCol2 = @Col2,@InnerCol1 = @Col1
GODECLARE @Col2 SMALLINT ,@Col1 INT
SELECT  @Col2 = 3 ,@Col1 = 4DECLARE @SQL NVARCHAR(1000)
SELECT  @SQL = 'select * from dbo.TestDynamicSQL
where Col2 = @InnerCol2 and Col1 = @InnerCol1'DECLARE @ParmDefinition NVARCHAR(500)
SET @ParmDefinition = N'@InnerCol2 smallint ,@InnerCol1 int'EXEC sp_executesql @SQL, @ParmDefinition, @InnerCol2 = @Col2,@InnerCol1 = @Col1GO

我们看到只有一个计数为8的计划,而不是像我们上述那样运行查询。 我们也可以只需要声明一次,然后我们只需要在执行之前更改参数的值,如下:

DECLARE @Col2 SMALLINT ,@Col1 INT
SELECT  @Col2 = 3 ,@Col1 = 4DECLARE @SQL NVARCHAR(1000)
SELECT  @SQL = 'select * from dbo.TestDynamicSQL
where Col2 = @InnerCol2 and Col1 = @InnerCol1' DECLARE @ParmDefinition NVARCHAR(500)
SET @ParmDefinition = N'@InnerCol2 smallint ,@InnerCol1 int'EXEC sp_executesql @SQL, @ParmDefinition, @InnerCol2 = @Col2,@InnerCol1 = @Col1--change param values and run the same query
SELECT  @Col2 = 2 ,@Col1 = 3
EXEC sp_executesql @SQL, @ParmDefinition, @InnerCol2 = @Col2,@InnerCol1 = @Col1

最终查询计划缓存次数和上述正确方式一致。正确使用sp_executesql对于性能非常有利,而且使用sp_executesql还可以为我们提供一些EXEC无法实现的功能。比如如何得到一个表中的行数? 利用EXEC我们需要使用一个临时表和填充,而用sp_executesql我们只需要使用一个输出变量。

SET STATISTICS IO ON
SET STATISTICS TIME ON
--EXEC (SQL)
DECLARE @Totalcount INT ,@SQL NVARCHAR(100)CREATE TABLE #temp (Totalcount INT )
SELECT  @SQL = 'Insert into #temp Select Count(*) from dbo.TestDynamicSQL'EXEC( @SQL)SELECT  @Totalcount = Totalcount
FROM    #tempSELECT  @Totalcount AS TotalcountDROP TABLE #temp
GO--sp_executesql
DECLARE @TableCount INT,
@SQL NVARCHAR(100)SELECT @SQL = N'SELECT @InnerTableCount = COUNT(*) FROM  dbo.TestDynamicSQL'EXEC SP_EXECUTESQL @SQL, N'@InnerTableCount INT OUTPUT', @TableCount OUTPUTSELECT @TableCount
GO

当然除了EXEC无法实现的功能外,最重要的一点则是SP_EXECUTESQL能够防止SQL注入问题。

总结

执行SQL动态查询SP_EXECUTESQL比EXEC性能更好,使得存储过程能够被重用,但是存储过程能够被重用的前提则是正确使用参数,使用参数化查询,否则SP_EXECUTESQL将不会提供任何性能益处。

转载于:https://www.cnblogs.com/CreateMyself/p/8277713.html

SQL Server-聚焦sp_executesql执行动态SQL查询性能真的比exec好?相关推荐

  1. 批处理bat文件连接SQL Server数据库并执行相关sql代码

    一.终于赶在八月的尾巴有了写东西的冲动了,恰巧昨天碰到一个问题,需要用bat给别人来执行某些sql语句. 二.单一执行 2.1:sql代码 use [DBName] SELECT top(1)* FR ...

  2. 使用sp_executesql存储过程执行动态SQL查询

    The sp_executesql stored procedure is used to execute dynamic SQL queries in SQL Server. A dynamic S ...

  3. SQL Server 执行计划(8) - 使用 SQL 执行计划进行查询性能调优

    在本系列的前几篇文章(见底部索引)中,我们介绍了SQL 执行计划的多个方面,我们讨论了执行计划是如何在内部生成的,不同类型的计划,主要组件和运算符以及如何阅读和分析使用不同工具生成的计划.在本文中,我 ...

  4. SQL Server-聚焦深入理解动态SQL查询(三十二)

    前言 之前有园友一直关注着我快点出SQL Server性能优化系列,博主我也对性能优化系列也有点小期待,本来打算利用周末写死锁以及避免死锁系列的接着进入SQL Server优化系列,但是在工作中长时间 ...

  5. mysql桦仔_Microsoft SQL Server 2005技术内幕:T-SQL查询笔记

    Microsoft SQL Server 2005技术内幕:T-SQL查询笔记 目录 f f f f f f f f 第二章 物理查询处理 分析,代数化,查询优化 f f f f f. 分析--> ...

  6. sql server死锁_如何使用扩展事件和SQL Server代理自动执行SQL Server死锁收集过程

    sql server死锁 介绍 (Introduction) This article is the last one of a series in which we discussed how to ...

  7. oracle中执行动态sql语句吗,oracle中有没有可动态执行sql语句的函数

    oracle中有没有可动态执行sql语句的函数 关注:233  答案:2  手机版 解决时间 2021-03-05 15:53 提问者祗剩寂寞 2021-03-04 22:38 oracle中有没有可 ...

  8. SQL server 系统优化--通过执行计划优化索引(1) (转)

    SQL server 系统优化--通过执行计划优化索引(1) 前几天,远离上海,到了温州,在客户的这边处理系统慢,该系统每天正常down机7次左右,在线人员一多,系统运行缓慢,严重影响业务操作,到了无 ...

  9. 05.SQL Server大数据群集小试牛刀--HDFS查询

    05.SQL Server大数据群集小试牛刀--HDFS查询 SQL Server大数据群集查询HDFS ,利用之前创建好的大数据群集,使用官方提供的测试数据进行测试.脚本是官方的脚本,要知道干了什么 ...

最新文章

  1. 洛谷P1074 靶形数独(跳舞链)
  2. 华科提出目标检测新方法:基于IoU-aware的定位改进,简单又有效
  3. jquery file upload ajax上传图片 简单使用
  4. iOS移除父控件中所有子控件的两种方式
  5. pmp知识点详解-项目大牛整理_PMP第七章:项目成本管理(1)项目管理核心知识点...
  6. Redis持久化-深入理解AOF,RDB
  7. 第二十期:想吃透监控系统,就这一篇够不够?
  8. python scatter 简书_写给 Pythonist 的 Spacemacs 入门指北
  9. node.js学习笔记之写文件
  10. 利用装饰器实现mock和api的局部分离切换
  11. 不是我不想动脑筋,给我一个支点看看——看《编程之美》,玩数独,大有乐趣...
  12. Win7下PDF文件无法显示缩略图的解决方法
  13. 饼图制作软件,饼图的制作方法
  14. 2017年中国大数据发展趋势和展望解读(上)
  15. 合肥工业大学的计算机专业的导师,合肥工业大学计算机与信息学院硕士生导师:程运安副教授...
  16. 图神经网络学习过程心得总结
  17. 了解Python 一
  18. 一个模仿微信群聊的H5页面
  19. 实验室安全考试易错题2022-2023
  20. B端产品经理产品心得(一)

热门文章

  1. SAP RETAIL初阶之门店的营业时间
  2. SAP 零售商品主数据修改物料组的方法
  3. SAP QM 含有HUM的检验批做UD时候的不同之处?
  4. 人脸识别最前沿在研究什么?
  5. 发展第三代AI:清华AI研究院基础理论研究中心成立,朱军任主任
  6. 推荐系统(5)—隐语义模型(LFM)
  7. 使用CNN分类签名和文本图像
  8. 盘点:2021年度物理学十大突破|《物理世界》
  9. MIT博士用概率编程让AI和人类一样看三维|NeurIPS 2021
  10. 工业环境中对机器学习的行业视角