SQL Server参数化查询 - 显式SQL语句与sp_executesql

时间:2018-06-15 02:08:34

标签: sql-server entity-framework tsql

对于参数化查询,使用显式SQL语句与sp_executesql之间是否存在性能(或任何其他)差异?

E.g。 SQL语句:

DECLARE @objectName SYSNAME, @objectType CHAR(2)

SELECT @objectName = N'sysrscols', @objectType='s' 

SELECT * 
FROM sys.objects 
WHERE [name] = @objectName AND [type] = @objectType

同样通过sp_executesql

EXEC sys.sp_executesql
   N'select * from sys.objects where [name] = @objectName and [type] = @objectType',
       N'@objectName SYSNAME, @objectType CHAR(2)',
       @objectName = N'sysrscols', @objectType = 's'

为什么实体框架使用sp_executesql?使用SQL Server Profiler查看它生成的查询时,如果它们只是SQL语句,则读取它们会容易得多。

2 个答案:

答案 0 :(得分:2)

区别在于,如果只有参数发生变化,SQL服务器将如何优化执行。如果使用这样的普通语句,则每次运行时都将按原样编译和执行语句。如果您使用sp_executesql并仅使用其他参数运行许多次,SQL服务器“很可能”重用执行计划,从而节省了性能:

  

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

(source on MSDN)

答案 1 :(得分:2)

细微差别是第一个查询未参数化。它是一批SQL语句,其中在查询中使用局部变量。这批语句作为批处理请求发送到SQL Server,没有参数,在编译和执行时。您可以从跟踪(Profiler或扩展事件)中看到事件类型为*batch*而不是*rpc*

当SqlClient应用程序(包括EF生成的SQL语句)使用参数化查询时(通过在SQL语句中向SqlCommand.Parameters集合和参数名称添加参数),请求作为RPC发送到SQL Server(远程过程调用) )请求定义参数值的位置,并与SQL语句本身分开传递。跟踪事件将显示rpc_*而不是sql_batch_*。 SqlClient API为此使用了sp_executesql。

参数化查询有许多好处,无论是由EF生成还是直接在代码中生成。其中包括:

  • 更安全,防止SQL注入
  • 消除了在字符串中转义引号的必要性
  • 避免以特定方式格式化日期字符串文字
  • 不需要小数分隔符
  • 通过促进计划缓存重用来提高性能

我将补充说,您在RPC调用的Profiler跟踪中看到的文本只是对底层TDS协议请求的逆向工程。如果您运行网络跟踪,则不会看到您在跟踪中看到的sp_executesql语句的引用。但参数化查询的要点是参数值以原生格式单独传递给SQL Server。