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

Sql server SQL Server参数化查询-显式SQL语句与sp_executesql,sql-server,entity-framework,tsql,Sql Server,Entity Framework,Tsql,对于参数化查询,使用显式SQL语句与使用sp_executesql之间是否存在性能或任何其他差异 例如SQL语句: DECLARE @objectName SYSNAME, @objectType CHAR(2) SELECT @objectName = N'sysrscols', @objectType='s' SELECT * FROM sys.objects WHERE [name] = @objectName AND [type] = @objectType 通过sp_exe

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

例如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执行相同的操作:


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

区别完全在于,如果只有参数更改,SQL Server将如何优化执行。如果您使用这样的普通语句,则该语句将按照每次运行时的原样编译和执行。如果使用sp_executesql并仅使用其他参数多次运行,SQL server可能会重用执行计划,从而节省性能:

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


区别完全在于,如果只有参数更改,SQL server将如何优化执行。如果您使用这样的普通语句,则该语句将按照每次运行时的原样编译和执行。如果使用sp_executesql并仅使用其他参数多次运行,SQL server可能会重用执行计划,从而节省性能:

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


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

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

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

更安全,防止SQL注入 不需要在字符串中转义引号 避免以特定方式格式化日期字符串文本 不需要小数分隔符 通过促进计划缓存重用提高性能
我要补充的是,您在RPC调用的探查器跟踪中看到的文本只是底层TDS协议请求的反向工程。如果运行网络跟踪,则不会看到对跟踪中的sp_executesql语句的引用。但是参数化查询的要点是,参数值以本机格式单独传递给SQL Server。

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

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

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

更安全,防止SQL注入 不需要在字符串中转义引号 避免以特定方式格式化日期字符串文本 不需要小数分隔符 通过促进计划缓存重用提高性能 我要补充的是,您在RPC调用的探查器跟踪中看到的文本只是底层TDS协议请求的反向工程。如果运行网络跟踪,则不会看到对跟踪中的sp_executesql语句的引用。
但参数化查询的要点是,参数值以本机格式单独传递给SQL Server。

这是出于性能原因。sp_executesql语句第1个参数已编译,仅当参数值更改时才可重用。这是出于性能原因。sp_executesql语句第1个参数已编译,如果只有参数值发生更改,则可以重新使用。感谢@Magisch,但SQL server不会缓存所有参数化查询的执行计划,无论它们是在sp_executesql中还是在普通sql语句中?实际上,它只是建议这样做比每次直接执行参数化sql字符串更好。SP似乎也是以这种方式缓存的@Andrew@Magisch你能引用陈述你主张的确切短语吗?AFAICT,如果SQL与以前对每个字符执行的SQL完全相同,则以前生成的执行计划将被重用。@TT。但是,如果您使用不同的参数执行完整的sql字符串,则不会出现这种情况,对吗?@Andrew您从哪里得到的?在第一个示例中,这是一个完整的SQL语句。如果更改其参数,则会更改语句,因为参数是语句的一部分。如果使用sp_executesql,则参数将单独提供,而不是语句的一部分,从而允许重用不包含参数的语句执行计划。感谢@Magisch,但SQL server不会缓存所有参数化查询的执行计划,无论它们是在sp_executesql中还是在普通sql语句中?实际上,它只是建议这样做比每次直接执行参数化sql字符串更好。SP似乎也是以这种方式缓存的@Andrew@Magisch你能引用陈述你主张的确切短语吗?AFAICT,如果SQL与以前对每个字符执行的SQL完全相同,则以前生成的执行计划将被重用。@TT。但是,如果您使用不同的参数执行完整的sql字符串,则不会出现这种情况,对吗?@Andrew您从哪里得到的?在第一个示例中,这是一个完整的SQL语句。如果更改其参数,则会更改语句,因为参数是语句的一部分。如果使用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'